summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRichard Yu <yurichard3839@gmail.com>2020-01-22 00:54:45 +0800
committerRichard Yu <yurichard3839@gmail.com>2020-01-27 01:26:10 +0800
commit51d38ee06dc871027387735185af5e2c4cb93736 (patch)
treee86ff9f59a989ed96d0b82f2d9000bd5d8e4fcd3
parent92da4a239eeb20274605c0d827b3449f67324f2b (diff)
luci-app-frp: add new packages
Signed-off-by: Richard Yu <yurichard3839@gmail.com>
-rw-r--r--applications/luci-app-frpc/Makefile13
-rw-r--r--applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js173
-rw-r--r--applications/luci-app-frpc/po/templates/frpc.pot356
-rw-r--r--applications/luci-app-frpc/root/usr/share/luci/menu.d/luci-app-frpc.json9
-rw-r--r--applications/luci-app-frpc/root/usr/share/rpcd/acl.d/luci-app-frpc.json8
-rw-r--r--applications/luci-app-frps/Makefile13
-rw-r--r--applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js114
-rw-r--r--applications/luci-app-frps/po/templates/frps.pot320
-rw-r--r--applications/luci-app-frps/root/usr/share/luci/menu.d/luci-app-frps.json9
-rw-r--r--applications/luci-app-frps/root/usr/share/rpcd/acl.d/luci-app-frps.json8
10 files changed, 1023 insertions, 0 deletions
diff --git a/applications/luci-app-frpc/Makefile b/applications/luci-app-frpc/Makefile
new file mode 100644
index 000000000..90a20c4bf
--- /dev/null
+++ b/applications/luci-app-frpc/Makefile
@@ -0,0 +1,13 @@
+# This is free software, licensed under the Apache License, Version 2.0
+
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=LuCI Support for frp client
+LUCI_DEPENDS:=+frpc
+
+PKG_LICENSE:=Apache-2.0
+PKG_MAINTAINER:=Richard Yu <yurichard3839@gmail.com>
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js b/applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js
new file mode 100644
index 000000000..da86569f1
--- /dev/null
+++ b/applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js
@@ -0,0 +1,173 @@
+'use strict';
+'require ui';
+'require form';
+'require tools.widgets as widgets';
+
+// [Widget, Option, Title, Description, {Param: 'Value'}],
+var startupConf = [
+ [form.Flag, 'stdout', _('Log stdout')],
+ [form.Flag, 'stderr', _('Log stderr')],
+ [widgets.UserSelect, 'user', _('Run daemon as user')],
+ [widgets.GroupSelect, 'group', _('Run daemon as group')],
+ [form.Flag, 'respawn', _('Respawn when crashed')],
+ [form.DynamicList, 'env', _('Environment variable'), _('OS environments pass to frp for config file template, see <a href="https://github.com/fatedier/frp#configuration-file-template">frp README</a>'), {placeholder: 'ENV_NAME=value'}],
+ [form.DynamicList, 'conf_inc', _('Additional configs'), _('Config files include in temporary config file'), {placeholder: '/etc/frp/frpc.d/frpc_full.ini'}]
+];
+
+var commonConf = [
+ [form.Value, 'server_addr', _('Server address'), _('ServerAddr specifies the address of the server to connect to.<br>By default, this value is "0.0.0.0".'), {datatype: 'ipaddr'}],
+ [form.Value, 'server_port', _('Server port'), _('ServerPort specifies the port to connect to the server on.<br>By default, this value is 7000.'), {datatype: 'port'}],
+ [form.Value, 'http_proxy', _('HTTP proxy'), _('HttpProxy specifies a proxy address to connect to the server through. If this value is "", the server will be connected to directly.<br>By default, this value is read from the "http_proxy" environment variable.')],
+ [form.ListValue, 'log_level', _('Log level'), _('LogLevel specifies the minimum log level. Valid values are "trace", "debug", "info", "warn", and "error".<br>By default, this value is "info".'), {values: ['trace', 'debug', 'info', 'warn', 'error']}],
+ [form.Flag, 'disable_log_color', _('Disable log color'), _('DisableLogColor disables log colors when LogWay == "console" when set to true.'), {datatype: 'bool', default: 'true'}],
+ [form.Value, 'token', _('Token'), _('Token specifies the authorization token used to create keys to be sent to the server. The server must have a matching token for authorization to succeed. <br>By default, this value is "".')],
+ [form.Value, 'admin_addr', _('Admin address'), _('AdminAddr specifies the address that the admin server binds to.<br>By default, this value is "127.0.0.1".'), {datatype: 'ipaddr'}],
+ [form.Value, 'admin_port', _('Admin port'), _('AdminPort specifies the port for the admin server to listen on. If this value is 0, the admin server will not be started.<br>By default, this value is 0.'), {datatype: 'port'}],
+ [form.Value, 'admin_user', _('Admin user'), _('AdminUser specifies the username that the admin server will use for login.<br>By default, this value is "admin".')],
+ [form.Value, 'admin_pwd', _('Admin password'), _('AdminPwd specifies the password that the admin server will use for login.<br>By default, this value is "admin".'), {password: true}],
+ [form.Value, 'assets_dir', _('Assets dir'), _('AssetsDir specifies the local directory that the admin server will load resources from. If this value is "", assets will be loaded from the bundled executable using statik.<br>By default, this value is "".')],
+ [form.Flag, 'tcp_mux', _('TCP mux'), _('TcpMux toggles TCP stream multiplexing. This allows multiple requests from a client to share a single TCP connection. If this value is true, the server must have TCP multiplexing enabled as well.<br>By default, this value is true.'), {datatype: 'bool', default: 'true'}],
+ [form.Value, 'user', _('User'), _('User specifies a prefix for proxy names to distinguish them from other clients. If this value is not "", proxy names will automatically be changed to "{user}.{proxy_name}".<br>By default, this value is "".')],
+ [form.Flag, 'login_fail_exit', _('Exit when login fail'), _('LoginFailExit controls whether or not the client should exit after a failed login attempt. If false, the client will retry until a login attempt succeeds.<br>By default, this value is true.'), {datatype: 'bool', default: 'true'}],
+ [form.ListValue, 'protocol', _('Protocol'), _('Protocol specifies the protocol to use when interacting with the server. Valid values are "tcp", "kcp", and "websocket".<br>By default, this value is "tcp".'), {values: ['tcp', 'kcp', 'websocket']}],
+ [form.Flag, 'tls_enable', _('TLS'), _('TLSEnable specifies whether or not TLS should be used when communicating with the server.'), {datatype: 'bool'}],
+ [form.Value, 'heartbeat_interval', _('Heartbeat interval'), _('HeartBeatInterval specifies at what interval heartbeats are sent to the server, in seconds. It is not recommended to change this value.<br>By default, this value is 30.'), {datatype: 'uinteger'}],
+ [form.Value, 'heartbeat_timeout', _('Heartbeat timeout'), _('HeartBeatTimeout specifies the maximum allowed heartbeat response delay before the connection is terminated, in seconds. It is not recommended to change this value.<br>By default, this value is 90.'), {datatype: 'uinteger'}]
+];
+
+var baseProxyConf = [
+ [form.ListValue, 'type', _('Proxy type'), _('ProxyType specifies the type of this proxy. Valid values include "tcp", "udp", "http", "https", "stcp", and "xtcp".<br>By default, this value is "tcp".'), {values: ['tcp', 'udp', 'http', 'https', 'stcp', 'xtcp']}],
+ [form.Flag, 'use_encryption', _('Encryption'), _('UseEncryption controls whether or not communication with the server will be encrypted. Encryption is done using the tokens supplied in the server and client configuration.<br>By default, this value is false.'), {datatype: 'bool'}],
+ [form.Flag, 'use_compression', _('Compression'), _('UseCompression controls whether or not communication with the server will be compressed.<br>By default, this value is false.'), {datatype: 'bool'}],
+ [form.Value, 'local_ip', _('Local IP'), _('LocalIp specifies the IP address or host name to proxy to.'), {datatype: 'ipaddr'}],
+ [form.Value, 'local_port', _('Local port'), _('LocalPort specifies the port to proxy to.'), {datatype: 'port'}],
+];
+
+var bindInfoConf = [
+ [form.Value, 'remote_port', _('Remote port'), _('If remote_port is 0, frps will assign a random port for you'), {datatype: 'port'}]
+];
+
+var domainConf = [
+ [form.Value, 'custom_domains', _('Custom domains')],
+ [form.Value, 'sub_domain', _('Subdomain')],
+];
+
+var httpProxyConf = [
+ [form.Value, 'locations', _('Locations')],
+ [form.Value, 'http_user', _('HTTP user')],
+ [form.Value, 'http_pwd', _('HTTP password')],
+ [form.Value, 'host_header_rewrite', _('Host header rewrite')],
+ // [form.Value, 'headers', _('Headers')], // FIXME
+];
+
+var stcpProxyConf = [
+ [form.ListValue, 'role', _('Role'), undefined, {values: ['server', 'visitor']}],
+ [form.Value, 'sk', _('Sk')],
+];
+
+function setParams(o, params) {
+ if (!params) return;
+ for (var key in params) {
+ var val = params[key];
+ if (key === 'values') {
+ for (var j = 0; j < val.length; j++) {
+ var args = val[j];
+ if (!Array.isArray(args))
+ args = [args];
+ o.value.apply(o, args);
+ }
+ } else if (key === 'depends') {
+ if (!Array.isArray(val))
+ val = [val];
+ for (var j = 0; j < val.length; j++) {
+ var args = val[j];
+ if (!Array.isArray(args))
+ args = [args];
+ o.depends.apply(o, args);
+ }
+ } else {
+ o[key] = params[key];
+ }
+ }
+ if (params['datatype'] === 'bool') {
+ o.enabled = 'true';
+ o.disabled = 'false';
+ }
+}
+
+function defTabOpts(s, t, opts, params) {
+ for (var i = 0; i < opts.length; i++) {
+ var opt = opts[i];
+ var o = s.taboption(t, opt[0], opt[1], opt[2], opt[3]);
+ setParams(o, opt[4]);
+ setParams(o, params);
+ }
+}
+
+function defOpts(s, opts, params) {
+ for (var i = 0; i < opts.length; i++) {
+ var opt = opts[i];
+ var o = s.option(opt[0], opt[1], opt[2], opt[3]);
+ setParams(o, opt[4]);
+ setParams(o, params);
+ }
+}
+
+return L.view.extend({
+ render: function() {
+ var m, s, o;
+
+ m = new form.Map('frpc', _('frp Client'));
+
+ s = m.section(form.NamedSection, 'common', 'conf');
+ s.dynamic = true;
+
+ s.tab('common', _('Common Settings'));
+ s.tab('init', _('Startup Settings'));
+
+ defTabOpts(s, 'common', commonConf, {optional: true});
+
+ o = s.taboption('init', form.SectionValue, 'init', form.TypedSection, 'init', _('Startup Settings'));
+ s = o.subsection;
+ s.anonymous = true;
+ s.dynamic = true;
+
+ defOpts(s, startupConf);
+
+ s = m.section(form.GridSection, 'conf', _('Proxy Settings'));
+ s.addremove = true;
+ s.filter = function(s) { return s !== 'common'; };
+ s.renderSectionAdd = function(extra_class) {
+ var el = form.GridSection.prototype.renderSectionAdd.apply(this, arguments),
+ nameEl = el.querySelector('.cbi-section-create-name');
+ ui.addValidator(nameEl, 'uciname', true, function(v) {
+ if (v === 'common') return _('Name can not be "common"');
+ return true;
+ }, 'blur', 'keyup');
+ return el;
+ }
+
+ s.tab('general', _('General Settings'));
+ s.tab('http', _('HTTP Settings'));
+
+ s.option(form.Value, 'type', _('Proxy type')).modalonly = false;
+ s.option(form.Value, 'local_ip', _('Local IP')).modalonly = false;
+ s.option(form.Value, 'local_port', _('Local port')).modalonly = false;
+
+ defTabOpts(s, 'general', baseProxyConf, {modalonly: true});
+
+ // TCP and UDP
+ defTabOpts(s, 'general', bindInfoConf, {optional: true, modalonly: true, depends: [{type: 'tcp'}, {type: 'udp'}]});
+
+ // HTTP and HTTPS
+ defTabOpts(s, 'http', domainConf, {optional: true, modalonly: true, depends: [{type: 'http'}, {type: 'https'}]});
+
+ // HTTP
+ defTabOpts(s, 'http', httpProxyConf, {optional: true, modalonly: true, depends: {type: 'http'}});
+
+ // STCP and XTCP
+ defTabOpts(s, 'general', stcpProxyConf, {modalonly: true, depends: [{type: 'stcp'}, {type: 'xtcp'}]});
+
+ return m.render();
+ }
+});
diff --git a/applications/luci-app-frpc/po/templates/frpc.pot b/applications/luci-app-frpc/po/templates/frpc.pot
new file mode 100644
index 000000000..a9c956923
--- /dev/null
+++ b/applications/luci-app-frpc/po/templates/frpc.pot
@@ -0,0 +1,356 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8"
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:14
+msgid "Additional configs"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:24
+msgid "Admin address"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:27
+msgid "Admin password"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:25
+msgid "Admin port"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:26
+msgid "Admin user"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:24
+msgid ""
+"AdminAddr specifies the address that the admin server binds to.<br>By "
+"default, this value is \"127.0.0.1\"."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:25
+msgid ""
+"AdminPort specifies the port for the admin server to listen on. If this "
+"value is 0, the admin server will not be started.<br>By default, this value "
+"is 0."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:27
+msgid ""
+"AdminPwd specifies the password that the admin server will use for login."
+"<br>By default, this value is \"admin\"."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:26
+msgid ""
+"AdminUser specifies the username that the admin server will use for login."
+"<br>By default, this value is \"admin\"."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:28
+msgid "Assets dir"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:28
+msgid ""
+"AssetsDir specifies the local directory that the admin server will load "
+"resources from. If this value is \"\", assets will be loaded from the "
+"bundled executable using statik.<br>By default, this value is \"\"."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:125
+msgid "Common Settings"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:41
+msgid "Compression"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:14
+msgid "Config files include in temporary config file"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:51
+msgid "Custom domains"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:22
+msgid "Disable log color"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:22
+msgid ""
+"DisableLogColor disables log colors when LogWay == \"console\" when set to "
+"true."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:40
+msgid "Encryption"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:13
+msgid "Environment variable"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:31
+msgid "Exit when login fail"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:150
+msgid "General Settings"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:151
+msgid "HTTP Settings"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:58
+msgid "HTTP password"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:20
+msgid "HTTP proxy"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:57
+msgid "HTTP user"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:60
+msgid "Headers"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:34
+msgid ""
+"HeartBeatInterval specifies at what interval heartbeats are sent to the "
+"server, in seconds. It is not recommended to change this value.<br>By "
+"default, this value is 30."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:35
+msgid ""
+"HeartBeatTimeout specifies the maximum allowed heartbeat response delay "
+"before the connection is terminated, in seconds. It is not recommended to "
+"change this value.<br>By default, this value is 90."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:34
+msgid "Heartbeat interval"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:35
+msgid "Heartbeat timeout"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:59
+msgid "Host header rewrite"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:20
+msgid ""
+"HttpProxy specifies a proxy address to connect to the server through. If "
+"this value is \"\", the server will be connected to directly.<br>By default, "
+"this value is read from the \"http_proxy\" environment variable."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:47
+msgid "If remote_port is 0, frps will assign a random port for you"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:42
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:154
+msgid "Local IP"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:43
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:155
+msgid "Local port"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:42
+msgid "LocalIp specifies the IP address or host name to proxy to."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:43
+msgid "LocalPort specifies the port to proxy to."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:56
+msgid "Locations"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:21
+msgid "Log level"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:9
+msgid "Log stderr"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:8
+msgid "Log stdout"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:21
+msgid ""
+"LogLevel specifies the minimum log level. Valid values are \"trace\", \"debug"
+"\", \"info\", \"warn\", and \"error\".<br>By default, this value is \"info\"."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:31
+msgid ""
+"LoginFailExit controls whether or not the client should exit after a failed "
+"login attempt. If false, the client will retry until a login attempt "
+"succeeds.<br>By default, this value is true."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:144
+msgid "Name can not be \"common\""
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:13
+msgid ""
+"OS environments pass to frp for config file template, see <a href=\"https://"
+"github.com/fatedier/frp#configuration-file-template\">frp README</a>"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:32
+msgid "Protocol"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:32
+msgid ""
+"Protocol specifies the protocol to use when interacting with the server. "
+"Valid values are \"tcp\", \"kcp\", and \"websocket\".<br>By default, this "
+"value is \"tcp\"."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:137
+msgid "Proxy Settings"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:39
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:153
+msgid "Proxy type"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:39
+msgid ""
+"ProxyType specifies the type of this proxy. Valid values include \"tcp\", "
+"\"udp\", \"http\", \"https\", \"stcp\", and \"xtcp\".<br>By default, this "
+"value is \"tcp\"."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:47
+msgid "Remote port"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:12
+msgid "Respawn when crashed"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:64
+msgid "Role"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:11
+msgid "Run daemon as group"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:10
+msgid "Run daemon as user"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:18
+msgid "Server address"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:19
+msgid "Server port"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:18
+msgid ""
+"ServerAddr specifies the address of the server to connect to.<br>By default, "
+"this value is \"0.0.0.0\"."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:19
+msgid ""
+"ServerPort specifies the port to connect to the server on.<br>By default, "
+"this value is 7000."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:65
+msgid "Sk"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:126
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:130
+msgid "Startup Settings"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:52
+msgid "Subdomain"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:29
+msgid "TCP mux"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:33
+msgid "TLS"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:33
+msgid ""
+"TLSEnable specifies whether or not TLS should be used when communicating "
+"with the server."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:29
+msgid ""
+"TcpMux toggles TCP stream multiplexing. This allows multiple requests from a "
+"client to share a single TCP connection. If this value is true, the server "
+"must have TCP multiplexing enabled as well.<br>By default, this value is "
+"true."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:23
+msgid "Token"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:23
+msgid ""
+"Token specifies the authorization token used to create keys to be sent to "
+"the server. The server must have a matching token for authorization to "
+"succeed. <br>By default, this value is \"\"."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:41
+msgid ""
+"UseCompression controls whether or not communication with the server will be "
+"compressed.<br>By default, this value is false."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:40
+msgid ""
+"UseEncryption controls whether or not communication with the server will be "
+"encrypted. Encryption is done using the tokens supplied in the server and "
+"client configuration.<br>By default, this value is false."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:30
+msgid "User"
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:30
+msgid ""
+"User specifies a prefix for proxy names to distinguish them from other "
+"clients. If this value is not \"\", proxy names will automatically be "
+"changed to \"{user}.{proxy_name}\".<br>By default, this value is \"\"."
+msgstr ""
+
+#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:120
+#: applications/luci-app-frpc/root/usr/share/luci/menu.d/luci-app-frpc.json:3
+msgid "frp Client"
+msgstr ""
diff --git a/applications/luci-app-frpc/root/usr/share/luci/menu.d/luci-app-frpc.json b/applications/luci-app-frpc/root/usr/share/luci/menu.d/luci-app-frpc.json
new file mode 100644
index 000000000..26a0f2b1c
--- /dev/null
+++ b/applications/luci-app-frpc/root/usr/share/luci/menu.d/luci-app-frpc.json
@@ -0,0 +1,9 @@
+{
+ "admin/services/frpc": {
+ "title": "frp Client",
+ "action": {
+ "type": "view",
+ "path": "frpc"
+ }
+ }
+}
diff --git a/applications/luci-app-frpc/root/usr/share/rpcd/acl.d/luci-app-frpc.json b/applications/luci-app-frpc/root/usr/share/rpcd/acl.d/luci-app-frpc.json
new file mode 100644
index 000000000..970b95780
--- /dev/null
+++ b/applications/luci-app-frpc/root/usr/share/rpcd/acl.d/luci-app-frpc.json
@@ -0,0 +1,8 @@
+{
+ "luci-app-frpc": {
+ "description": "Grant access to LuCI app frpc",
+ "write": {
+ "uci": ["frpc"]
+ }
+ }
+}
diff --git a/applications/luci-app-frps/Makefile b/applications/luci-app-frps/Makefile
new file mode 100644
index 000000000..4d77b03c0
--- /dev/null
+++ b/applications/luci-app-frps/Makefile
@@ -0,0 +1,13 @@
+# This is free software, licensed under the Apache License, Version 2.0
+
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=LuCI Support for frp server
+LUCI_DEPENDS:=+frps
+
+PKG_LICENSE:=Apache-2.0
+PKG_MAINTAINER:=Richard Yu <yurichard3839@gmail.com>
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js b/applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js
new file mode 100644
index 000000000..d941a9937
--- /dev/null
+++ b/applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js
@@ -0,0 +1,114 @@
+'use strict';
+'require form';
+'require tools.widgets as widgets';
+
+// [Widget, Option, Title, Description, {Param: 'Value'}],
+var startupConf = [
+ [form.Flag, 'stdout', _('Log stdout')],
+ [form.Flag, 'stderr', _('Log stderr')],
+ [widgets.UserSelect, 'user', _('Run daemon as user')],
+ [widgets.GroupSelect, 'group', _('Run daemon as group')],
+ [form.Flag, 'respawn', _('Respawn when crashed')],
+ [form.DynamicList, 'env', _('Environment variable'), _('OS environments pass to frp for config file template, see <a href="https://github.com/fatedier/frp#configuration-file-template">frp README</a>'), {placeholder: 'ENV_NAME=value'}],
+ [form.DynamicList, 'conf_inc', _('Additional configs'), _('Config files include in temporary config file'), {placeholder: '/etc/frp/frps.d/frps_full.ini'}]
+];
+
+var commonConf = [
+ [form.Value, 'bind_addr', _('Bind address'), _('BindAddr specifies the address that the server binds to.<br>By default, this value is "0.0.0.0".'), {datatype: 'ipaddr'}],
+ [form.Value, 'bind_port', _('Bind port'), _('BindPort specifies the port that the server listens on.<br>By default, this value is 7000.'), {datatype: 'port'}],
+ [form.Value, 'bind_udp_port', _('UDP bind port'), _('BindUdpPort specifies the UDP port that the server listens on. If this value is 0, the server will not listen for UDP connections.<br>By default, this value is 0'), {datatype: 'port'}],
+ [form.Value, 'kcp_bind_port', _('KCP bind port'), _('BindKcpPort specifies the KCP port that the server listens on. If this value is 0, the server will not listen for KCP connections.<br>By default, this value is 0.'), {datatype: 'port'}],
+ [form.Value, 'proxy_bind_addr', _('Proxy bind address'), _('ProxyBindAddr specifies the address that the proxy binds to. This value may be the same as BindAddr.<br>By default, this value is "0.0.0.0".'), {datatype: 'ipaddr'}],
+ [form.Value, 'vhost_http_port', _('Vhost HTTP port'), _('VhostHttpPort specifies the port that the server listens for HTTP Vhost requests. If this value is 0, the server will not listen for HTTP requests.<br>By default, this value is 0.'), {datatype: 'port'}],
+ [form.Value, 'vhost_https_port', _('Vhost HTTPS port'), _('VhostHttpsPort specifies the port that the server listens for HTTPS Vhost requests. If this value is 0, the server will not listen for HTTPS requests.<br>By default, this value is 0.'), {datatype: 'port'}],
+ [form.Value, 'vhost_http_timeout', _('Vhost HTTP timeout'), _('VhostHttpTimeout specifies the response header timeout for the Vhost HTTP server, in seconds.<br>By default, this value is 60.'), {datatype: 'uinteger'}],
+ [form.Value, 'dashboard_addr', _('Dashboard address'), _('DashboardAddr specifies the address that the dashboard binds to.<br>By default, this value is "0.0.0.0".'), {datatype: 'ipaddr'}],
+ [form.Value, 'dashboard_port', _('Dashboard port'), _('DashboardPort specifies the port that the dashboard listens on. If this value is 0, the dashboard will not be started.<br>By default, this value is 0.'), {datatype: 'port'}],
+ [form.Value, 'dashboard_user', _('Dashboard user'), _('DashboardUser specifies the username that the dashboard will use for login.<br>By default, this value is "admin".')],
+ [form.Value, 'dashboard_pwd', _('Dashboard password'), _('DashboardPwd specifies the password that the dashboard will use for login.<br>By default, this value is "admin".'), {password: true}],
+ [form.Value, 'assets_dir', _('Assets dir'), _('AssetsDir specifies the local directory that the dashboard will load resources from. If this value is "", assets will be loaded from the bundled executable using statik.<br>By default, this value is "".')],
+ [form.Value, 'log_file', _('Log file'), _('LogFile specifies a file where logs will be written to. This value will only be used if LogWay is set appropriately.<br>By default, this value is "console".')],
+ [form.ListValue, 'log_level', _('Log level'), _('LogLevel specifies the minimum log level. Valid values are "trace", "debug", "info", "warn", and "error".<br>By default, this value is "info".'), {values: ['trace', 'debug', 'info', 'warn', 'error']}],
+ [form.Value, 'log_max_days', _('Log max days'), _('LogMaxDays specifies the maximum number of days to store log information before deletion. This is only used if LogWay == "file".<br>By default, this value is 0.'), {datatype: 'uinteger'}],
+ [form.Flag, 'disable_log_color', _('Disable log color'), _('DisableLogColor disables log colors when LogWay == "console" when set to true.<br>By default, this value is false.'), {datatype: 'bool', default: 'true'}],
+ [form.Value, 'token', _('Token'), _('Token specifies the authorization token used to authenticate keys received from clients. Clients must have a matching token to be authorized to use the server.<br>By default, this value is "".')],
+ [form.Value, 'subdomain_host', _('Subdomain host'), _('SubDomainHost specifies the domain that will be attached to sub-domains requested by the client when using Vhost proxying. For example, if this value is set to "frps.com" and the client requested the subdomain "test", the resulting URL would be "test.frps.com".<br>By default, this value is "".')],
+ [form.Flag, 'tcp_mux', _('TCP mux'), _('TcpMux toggles TCP stream multiplexing. This allows multiple requests from a client to share a single TCP connection.<br>By default, this value is true.'), {datatype: 'bool', default: 'true'}],
+ [form.Value, 'custom_404_page', _('Custom 404 page'), _('Custom404Page specifies a path to a custom 404 page to display. If this value is "", a default page will be displayed.<br>By default, this value is "".')],
+ [form.Value, 'allow_ports', _('Allow ports'), _('AllowPorts specifies a set of ports that clients are able to proxy to. If the length of this value is 0, all ports are allowed.<br>By default, this value is an empty set.')],
+ [form.Value, 'max_ports_per_client', _('Max ports per client'), _('MaxPortsPerClient specifies the maximum number of ports a single client may proxy to. If this value is 0, no limit will be applied.<br>By default, this value is 0.'), {datatype: 'uinteger'}],
+ [form.Value, 'heartbeat_timeout', _('Heartbeat timeout'), _('HeartBeatTimeout specifies the maximum time to wait for a heartbeat before terminating the connection. It is not recommended to change this value.<br>By default, this value is 90.'), {datatype: 'uinteger'}]
+];
+
+function setParams(o, params) {
+ if (!params) return;
+ for (var key in params) {
+ var val = params[key];
+ if (key === 'values') {
+ for (var j = 0; j < val.length; j++) {
+ var args = val[j];
+ if (!Array.isArray(args))
+ args = [args];
+ o.value.apply(o, args);
+ }
+ } else if (key === 'depends') {
+ if (!Array.isArray(val))
+ val = [val];
+ for (var j = 0; j < val.length; j++) {
+ var args = val[j];
+ if (!Array.isArray(args))
+ args = [args];
+ o.depends.apply(o, args);
+ }
+ } else {
+ o[key] = params[key];
+ }
+ }
+ if (params['datatype'] === 'bool') {
+ o.enabled = 'true';
+ o.disabled = 'false';
+ }
+}
+
+function defTabOpts(s, t, opts, params) {
+ for (var i = 0; i < opts.length; i++) {
+ var opt = opts[i];
+ var o = s.taboption(t, opt[0], opt[1], opt[2], opt[3]);
+ setParams(o, opt[4]);
+ setParams(o, params);
+ }
+}
+
+function defOpts(s, opts, params) {
+ for (var i = 0; i < opts.length; i++) {
+ var opt = opts[i];
+ var o = s.option(opt[0], opt[1], opt[2], opt[3]);
+ setParams(o, opt[4]);
+ setParams(o, params);
+ }
+}
+
+return L.view.extend({
+ render: function() {
+ var m, s, o;
+
+ m = new form.Map('frps', _('frp Server'));
+
+ s = m.section(form.NamedSection, 'common', 'conf');
+ s.dynamic = true;
+
+ s.tab('common', _('Common settings'));
+ s.tab('init', _('Startup settings'));
+
+ defTabOpts(s, 'common', commonConf, {optional: true});
+
+ o = s.taboption('init', form.SectionValue, 'init', form.TypedSection, 'init', _('Startup settings'));
+ s = o.subsection;
+ s.anonymous = true;
+ s.dynamic = true;
+
+ defOpts(s, startupConf);
+
+ return m.render();
+ }
+});
diff --git a/applications/luci-app-frps/po/templates/frps.pot b/applications/luci-app-frps/po/templates/frps.pot
new file mode 100644
index 000000000..11c320870
--- /dev/null
+++ b/applications/luci-app-frps/po/templates/frps.pot
@@ -0,0 +1,320 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8"
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:13
+msgid "Additional configs"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:38
+msgid "AllowPorts"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:38
+msgid ""
+"AllowPorts specifies a set of ports that clients are able to proxy to. If "
+"the length of this value is 0, all ports are allowed.<br>By default, this "
+"value is an empty set."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:29
+msgid "AssetsDir"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:29
+msgid ""
+"AssetsDir specifies the local directory that the dashboard will load "
+"resources from. If this value is \"\", assets will be loaded from the "
+"bundled executable using statik.<br>By default, this value is \"\"."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:17
+msgid "BindAddr"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:17
+msgid ""
+"BindAddr specifies the address that the server binds to.<br>By default, this "
+"value is \"0.0.0.0\"."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:20
+msgid "BindKcpPort"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:20
+msgid ""
+"BindKcpPort specifies the KCP port that the server listens on. If this value "
+"is 0, the server will not listen for KCP connections.<br>By default, this "
+"value is 0."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:18
+msgid "BindPort"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:18
+msgid ""
+"BindPort specifies the port that the server listens on.<br>By default, this "
+"value is 7000."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:19
+msgid "BindUdpPort"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:19
+msgid ""
+"BindUdpPort specifies the UDP port that the server listens on. If this value "
+"is 0, the server will not listen for UDP connections.<br>By default, this "
+"value is 0"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:101
+msgid "Common settings"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:13
+msgid "Config files include in temporary config file"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:37
+msgid "Custom404Page"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:37
+msgid ""
+"Custom404Page specifies a path to a custom 404 page to display. If this "
+"value is \"\", a default page will be displayed.<br>By default, this value "
+"is \"\"."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:25
+msgid "DashboardAddr"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:25
+msgid ""
+"DashboardAddr specifies the address that the dashboard binds to.<br>By "
+"default, this value is \"0.0.0.0\"."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:26
+msgid "DashboardPort"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:26
+msgid ""
+"DashboardPort specifies the port that the dashboard listens on. If this "
+"value is 0, the dashboard will not be started.<br>By default, this value is "
+"0."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:28
+msgid "DashboardPwd"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:28
+msgid ""
+"DashboardPwd specifies the password that the dashboard will use for login."
+"<br>By default, this value is \"admin\"."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:27
+msgid "DashboardUser"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:27
+msgid ""
+"DashboardUser specifies the username that the dashboard will use for login."
+"<br>By default, this value is \"admin\"."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:33
+msgid "DisableLogColor"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:33
+msgid ""
+"DisableLogColor disables log colors when LogWay == \"console\" when set to "
+"true.<br>By default, this value is false."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:12
+msgid "Environment variable"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:41
+msgid "HeartBeatTimeout"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:41
+msgid ""
+"HeartBeatTimeout specifies the maximum time to wait for a heartbeat before "
+"terminating the connection. It is not recommended to change this value."
+"<br>By default, this value is 90."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:8
+msgid "Log stderr"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:7
+msgid "Log stdout"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:30
+msgid "LogFile"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:30
+msgid ""
+"LogFile specifies a file where logs will be written to. This value will only "
+"be used if LogWay is set appropriately.<br>By default, this value is "
+"\"console\"."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:31
+msgid "LogLevel"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:31
+msgid ""
+"LogLevel specifies the minimum log level. Valid values are \"trace\", \"debug"
+"\", \"info\", \"warn\", and \"error\".<br>By default, this value is \"info\"."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:32
+msgid "LogMaxDays"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:32
+msgid ""
+"LogMaxDays specifies the maximum number of days to store log information "
+"before deletion. This is only used if LogWay == \"file\".<br>By default, "
+"this value is 0."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:39
+msgid "MaxPoolCount"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:39
+msgid ""
+"MaxPoolCount specifies the maximum pool size for each proxy.<br>By default, "
+"this value is 5."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:40
+msgid "MaxPortsPerClient"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:40
+msgid ""
+"MaxPortsPerClient specifies the maximum number of ports a single client may "
+"proxy to. If this value is 0, no limit will be applied.<br>By default, this "
+"value is 0."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:12
+msgid ""
+"OS environments pass to frp for config file template, see <a href=\"https://"
+"github.com/fatedier/frp#configuration-file-template\">frp README</a>"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:21
+msgid "ProxyBindAddr"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:21
+msgid ""
+"ProxyBindAddr specifies the address that the proxy binds to. This value may "
+"be the same as BindAddr.<br>By default, this value is \"0.0.0.0\"."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:11
+msgid "Respawn when crashed"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:10
+msgid "Run daemon as group"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:9
+msgid "Run daemon as user"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:102
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:106
+msgid "Startup settings"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:35
+msgid "SubDomainHost"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:35
+msgid ""
+"SubDomainHost specifies the domain that will be attached to sub-domains "
+"requested by the client when using Vhost proxying. For example, if this "
+"value is set to \"frps.com\" and the client requested the subdomain \"test"
+"\", the resulting URL would be \"test.frps.com\".<br>By default, this value "
+"is \"\"."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:36
+msgid "TcpMux"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:36
+msgid ""
+"TcpMux toggles TCP stream multiplexing. This allows multiple requests from a "
+"client to share a single TCP connection.<br>By default, this value is true."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:34
+msgid "Token"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:34
+msgid ""
+"Token specifies the authorization token used to authenticate keys received "
+"from clients. Clients must have a matching token to be authorized to use the "
+"server.<br>By default, this value is \"\"."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:22
+msgid "VhostHttpPort"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:22
+msgid ""
+"VhostHttpPort specifies the port that the server listens for HTTP Vhost "
+"requests. If this value is 0, the server will not listen for HTTP requests."
+"<br>By default, this value is 0."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:24
+msgid "VhostHttpTimeout"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:24
+msgid ""
+"VhostHttpTimeout specifies the response header timeout for the Vhost HTTP "
+"server, in seconds.<br>By default, this value is 60."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:23
+msgid "VhostHttpsPort"
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:23
+msgid ""
+"VhostHttpsPort specifies the port that the server listens for HTTPS Vhost "
+"requests. If this value is 0, the server will not listen for HTTPS requests."
+"<br>By default, this value is 0."
+msgstr ""
+
+#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:96
+#: applications/luci-app-frps/root/usr/share/luci/menu.d/luci-app-frps.json:3
+msgid "frp Server"
+msgstr ""
diff --git a/applications/luci-app-frps/root/usr/share/luci/menu.d/luci-app-frps.json b/applications/luci-app-frps/root/usr/share/luci/menu.d/luci-app-frps.json
new file mode 100644
index 000000000..3b8711451
--- /dev/null
+++ b/applications/luci-app-frps/root/usr/share/luci/menu.d/luci-app-frps.json
@@ -0,0 +1,9 @@
+{
+ "admin/services/frps": {
+ "title": "frp Server",
+ "action": {
+ "type": "view",
+ "path": "frps"
+ }
+ }
+}
diff --git a/applications/luci-app-frps/root/usr/share/rpcd/acl.d/luci-app-frps.json b/applications/luci-app-frps/root/usr/share/rpcd/acl.d/luci-app-frps.json
new file mode 100644
index 000000000..8c0f8f5a0
--- /dev/null
+++ b/applications/luci-app-frps/root/usr/share/rpcd/acl.d/luci-app-frps.json
@@ -0,0 +1,8 @@
+{
+ "luci-app-frps": {
+ "description": "Grant access to LuCI app frps",
+ "write": {
+ "uci": ["frps"]
+ }
+ }
+}