Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
455dc47916
|
||
|
|
911080ae81
|
||
|
|
edd7cc44de
|
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"name": "sockethub-1",
|
||||||
|
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0DbJHhPvJTaKfPHoOa+i\nr49DPFVvAgUVsbVUsgRvnAW/ngoRwhSHTaHBIfmuvNI/6yoSTy2xZzIgsDGZDeEe\n/gSlmUjbh4Udex9pZ3fotdPjTpqDQMk8KpmCjF9SWstfYwYhcx2oLiImdeSLvn6l\nyMrpx/rieDHn8rEs/cvqkrCCPLtOxLByC92iy5wkz64PouU0/VUud0G7o02pTXd4\n0WULNpehRGl3paNmqCQmShUxeRMkJYOYspHyc13qwQHD35hOBk7A6QDDRHMRbcoI\nLE36q5Mkyh2YGbDhSemoyh+lwqYOHfYJy9gWrIvPEbg6us0yXK1xq1kifPKB9zQj\n4QIDAQAB\n-----END PUBLIC KEY-----\n"
|
||||||
|
}
|
||||||
+1
-1
Submodule nodes updated: 9fd20154f7...a0396e959b
@@ -40,6 +40,7 @@ production_run_list = %w(
|
|||||||
kosmos-ipfs::nginx_public_gateway
|
kosmos-ipfs::nginx_public_gateway
|
||||||
kosmos-mastodon::nginx
|
kosmos-mastodon::nginx
|
||||||
remotestorage_discourse::nginx
|
remotestorage_discourse::nginx
|
||||||
|
sockethub::nginx
|
||||||
role[tor_proxy]
|
role[tor_proxy]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -1,10 +1,11 @@
|
|||||||
name "sockethub"
|
name "sockethub"
|
||||||
|
|
||||||
default_attributes 'sockethub' => {
|
default_attributes 'kosmos_redis' => {
|
||||||
'version' => '5.0.0-alpha.1'
|
'requirepass' => false
|
||||||
}
|
}
|
||||||
|
|
||||||
run_list %w(
|
run_list %w(
|
||||||
|
kosmos_redis::default
|
||||||
sockethub::default
|
sockethub::default
|
||||||
sockethub::proxy
|
sockethub::firewall
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,3 +3,4 @@
|
|||||||
default["kosmos_redis"]["add_redisio_repository"] = true
|
default["kosmos_redis"]["add_redisio_repository"] = true
|
||||||
default["kosmos_redis"]["package_name"] = "redis"
|
default["kosmos_redis"]["package_name"] = "redis"
|
||||||
default["kosmos_redis"]["port"] = 6379
|
default["kosmos_redis"]["port"] = 6379
|
||||||
|
default["kosmos_redis"]["requirepass"] = true
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
include_recipe "kosmos_redis::repo" if node["kosmos_redis"]["add_redisio_repository"]
|
include_recipe "kosmos_redis::repo" if node["kosmos_redis"]["add_redisio_repository"]
|
||||||
|
|
||||||
credentials = data_bag_item("credentials", "redis")
|
credentials = data_bag_item("credentials", "redis") if node["kosmos_redis"]["requirepass"]
|
||||||
|
|
||||||
redisio_install "default" do
|
redisio_install "default" do
|
||||||
package_install true
|
package_install true
|
||||||
@@ -17,5 +17,5 @@ end
|
|||||||
redisio_server node["kosmos_redis"]["port"].to_s do
|
redisio_server node["kosmos_redis"]["port"].to_s do
|
||||||
package_install true
|
package_install true
|
||||||
package_name node["kosmos_redis"]["package_name"]
|
package_name node["kosmos_redis"]["package_name"]
|
||||||
requirepass credentials["password"]
|
requirepass credentials["password"] if node["kosmos_redis"]["requirepass"]
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
sockethub CHANGELOG
|
CHANGELOG
|
||||||
===================
|
=========
|
||||||
|
|
||||||
|
0.3.0
|
||||||
|
-----
|
||||||
|
- Update to sockethub 5.0.0-alpha.25
|
||||||
|
- Serve via openresty proxy (tls_cert_for + openresty_site) instead of
|
||||||
|
a directly managed nginx on the VM
|
||||||
|
- Generate sockethub.config.json (trustProxy, reconnectIpSource)
|
||||||
|
- Restrict the service port to the internal 10.1.1.0/24 network
|
||||||
|
|
||||||
0.1.0
|
0.1.0
|
||||||
-----
|
-----
|
||||||
- [Greg Karékinian] - Initial release of sockethub
|
- Initial release of sockethub cookbook
|
||||||
|
|||||||
@@ -7,27 +7,10 @@ Attributes
|
|||||||
----------
|
----------
|
||||||
|
|
||||||
#### sockethub::default
|
#### sockethub::default
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>Key</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Description</th>
|
|
||||||
<th>Default</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><tt>['sockethub']['port']</tt></td>
|
|
||||||
<td>Integer</td>
|
|
||||||
<td>The local port to run sockethub on</td>
|
|
||||||
<td><tt>10551</tt></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><tt>['sockethub']['external_port']</tt></td>
|
|
||||||
<td>Integer</td>
|
|
||||||
<td>The external port to run sockethub on. This will also open the port on the firewall</td>
|
|
||||||
<td><tt>10550</tt></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
Right now the nginx vhost is hardcoded: sockethub.kosmos.org
|
| Key | Type | Description | Default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
Sockethub will be available under https://sockethub.kosmos.org:10550
|
| `['sockethub']['version']` | String | The npm version of sockethub to install | `5.0.0-alpha.25` |
|
||||||
|
| `['sockethub']['port']` | Integer | The local port to run sockethub on | `10550` |
|
||||||
|
| `['sockethub']['domain']` | String | The public domain served by the openresty proxy | `sockethub.kosmos.org` |
|
||||||
|
| `['sockethub']['log_level']` | String | Console log level (error, warn, info, debug) | `info` |
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
node.default['sockethub']['port'] = '10551'
|
node.default['sockethub']['version'] = '5.0.0-alpha.25'
|
||||||
node.default['sockethub']['external_port'] = '10550'
|
node.default['sockethub']['port'] = '10550'
|
||||||
node.default['sockethub']['version'] = '4.1.0'
|
node.default['sockethub']['domain'] = 'sockethub.kosmos.org'
|
||||||
node.default['sockethub']['nginx']['server_name'] = 'sockethub.kosmos.org'
|
node.default['sockethub']['log_level'] = 'info'
|
||||||
node.default['sockethub']['debug_logs'] = 'sockethub*'
|
|
||||||
@@ -4,9 +4,9 @@ maintainer_email 'mail@kosmos.org'
|
|||||||
license 'MIT'
|
license 'MIT'
|
||||||
description 'Installs/Configures sockethub'
|
description 'Installs/Configures sockethub'
|
||||||
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
|
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
|
||||||
version '0.2.0'
|
version '0.3.0'
|
||||||
|
|
||||||
depends 'firewall'
|
depends 'firewall'
|
||||||
depends 'redisio'
|
depends 'kosmos-base'
|
||||||
depends 'kosmos-nodejs'
|
depends 'kosmos-nodejs'
|
||||||
depends 'kosmos-nginx'
|
depends 'kosmos_openresty'
|
||||||
@@ -3,10 +3,7 @@
|
|||||||
# Recipe:: default
|
# Recipe:: default
|
||||||
#
|
#
|
||||||
|
|
||||||
include_recipe 'redisio::default'
|
node.override["kosmos_nodejs"]["version"] = "24.21.0"
|
||||||
include_recipe 'redisio::enable'
|
|
||||||
|
|
||||||
node.override["kosmos_nodejs"]["version"] = "24.18.0"
|
|
||||||
include_recipe 'kosmos-nodejs'
|
include_recipe 'kosmos-nodejs'
|
||||||
|
|
||||||
user = "sockethub"
|
user = "sockethub"
|
||||||
@@ -27,6 +24,24 @@ end
|
|||||||
|
|
||||||
npm_package "sockethub" do
|
npm_package "sockethub" do
|
||||||
version node['sockethub']['version']
|
version node['sockethub']['version']
|
||||||
|
auto_update false
|
||||||
|
end
|
||||||
|
|
||||||
|
directory "/etc/sockethub" do
|
||||||
|
owner user
|
||||||
|
group group
|
||||||
|
mode 0750
|
||||||
|
end
|
||||||
|
|
||||||
|
template "/etc/sockethub/sockethub.config.json" do
|
||||||
|
source "sockethub.config.json.erb"
|
||||||
|
owner user
|
||||||
|
group group
|
||||||
|
mode 0640
|
||||||
|
variables port: node['sockethub']['port'],
|
||||||
|
domain: node['sockethub']['domain'],
|
||||||
|
log_level: node['sockethub']['log_level']
|
||||||
|
notifies :restart, 'systemd_unit[sockethub_nodejs.service]', :delayed
|
||||||
end
|
end
|
||||||
|
|
||||||
execute "systemctl daemon-reload" do
|
execute "systemctl daemon-reload" do
|
||||||
@@ -34,17 +49,6 @@ execute "systemctl daemon-reload" do
|
|||||||
action :nothing
|
action :nothing
|
||||||
end
|
end
|
||||||
|
|
||||||
environment_variables = {
|
|
||||||
'PORT' => node['sockethub']['port'],
|
|
||||||
# Use the second database (index starts at 0)
|
|
||||||
'REDIS_URL' => "redis://localhost:6379/1"
|
|
||||||
}
|
|
||||||
unless node['sockethub']['debug_logs'].nil?
|
|
||||||
environment_variables['DEBUG'] = node['sockethub']['debug_logs']
|
|
||||||
end
|
|
||||||
|
|
||||||
environment = environment_variables.map{|k, v| "'#{k}=#{v}'"}.join(' ')
|
|
||||||
|
|
||||||
systemd_unit "sockethub_nodejs.service" do
|
systemd_unit "sockethub_nodejs.service" do
|
||||||
content <<-EOF
|
content <<-EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
@@ -56,7 +60,7 @@ After=redis@6379.service
|
|||||||
ExecStart=#{entry}
|
ExecStart=#{entry}
|
||||||
User=#{user}
|
User=#{user}
|
||||||
Group=#{group}
|
Group=#{group}
|
||||||
Environment=#{environment}
|
Environment=SOCKETHUB_CONFIG=/etc/sockethub/sockethub.config.json
|
||||||
Restart=always
|
Restart=always
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ unless node.chef_environment == "development"
|
|||||||
include_recipe "kosmos-base::firewall"
|
include_recipe "kosmos-base::firewall"
|
||||||
|
|
||||||
firewall_rule 'sockethub' do
|
firewall_rule 'sockethub' do
|
||||||
port node['sockethub']['external_port'].to_i
|
port node['sockethub']['port'].to_i
|
||||||
|
source '10.1.1.0/24'
|
||||||
protocol :tcp
|
protocol :tcp
|
||||||
command :allow
|
command :allow
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#
|
||||||
|
# Cookbook Name:: sockethub
|
||||||
|
# Recipe:: nginx
|
||||||
|
#
|
||||||
|
|
||||||
|
domain = node['sockethub']['domain']
|
||||||
|
|
||||||
|
sockethub_node = search(:node, 'role:sockethub').first
|
||||||
|
|
||||||
|
if sockethub_node.nil?
|
||||||
|
Chef::Log.warn("No node found with 'sockethub' role. Not configuring openresty site.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
tls_cert_for domain do
|
||||||
|
auth 'gandi_dns'
|
||||||
|
action :create
|
||||||
|
end
|
||||||
|
|
||||||
|
openresty_site domain do
|
||||||
|
template 'nginx_conf_sockethub.erb'
|
||||||
|
variables domain: domain,
|
||||||
|
upstream_host: sockethub_node['knife_zero']['host'],
|
||||||
|
upstream_port: node['sockethub']['port'],
|
||||||
|
ssl_cert: "/etc/letsencrypt/live/#{domain}/fullchain.pem",
|
||||||
|
ssl_key: "/etc/letsencrypt/live/#{domain}/privkey.pem"
|
||||||
|
end
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
#
|
|
||||||
# Cookbook Name:: sockethub
|
|
||||||
# Recipe:: proxy
|
|
||||||
#
|
|
||||||
|
|
||||||
include_recipe 'sockethub::firewall'
|
|
||||||
include_recipe 'kosmos-nginx'
|
|
||||||
include_recipe "kosmos-base::letsencrypt"
|
|
||||||
|
|
||||||
server_name = node['sockethub']['nginx']['server_name']
|
|
||||||
|
|
||||||
nginx_post_hook = <<-EOF
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
systemctl reload nginx
|
|
||||||
EOF
|
|
||||||
|
|
||||||
file "/etc/letsencrypt/renewal-hooks/post/nginx" do
|
|
||||||
content nginx_post_hook
|
|
||||||
mode 0755
|
|
||||||
owner "root"
|
|
||||||
group "root"
|
|
||||||
end
|
|
||||||
|
|
||||||
gandi_api_credentials = data_bag_item('credentials', 'gandi_api')
|
|
||||||
|
|
||||||
template "/root/gandi_dns_certbot_hook.sh" do
|
|
||||||
variables gandi_api_key: gandi_api_credentials["key"]
|
|
||||||
mode 0770
|
|
||||||
end
|
|
||||||
|
|
||||||
# Generate a Let's Encrypt cert (only if no cert has been generated before).
|
|
||||||
# The systemd timer will take care of renewing
|
|
||||||
execute "letsencrypt cert for sockethub" do
|
|
||||||
command "certbot certonly --manual --preferred-challenges dns --manual-public-ip-logging-ok --agree-tos --manual-auth-hook \"/root/gandi_dns_certbot_hook.sh auth\" --manual-cleanup-hook \"/root/gandi_dns_certbot_hook.sh cleanup\" --deploy-hook \"/etc/letsencrypt/renewal-hooks/post/nginx\" --email ops@kosmos.org -d #{server_name} -n"
|
|
||||||
not_if do
|
|
||||||
File.exist?("/etc/letsencrypt/live/#{server_name}/fullchain.pem")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
template "#{node['nginx']['dir']}/sites-available/#{server_name}" do
|
|
||||||
source 'nginx_conf_sockethub.erb'
|
|
||||||
owner 'www-data'
|
|
||||||
mode 0640
|
|
||||||
variables sockethub_port: node['sockethub']['port'],
|
|
||||||
sockethub_external_port: node['sockethub']['external_port'],
|
|
||||||
server_name: server_name,
|
|
||||||
ssl_cert: "/etc/letsencrypt/live/#{server_name}/fullchain.pem",
|
|
||||||
ssl_key: "/etc/letsencrypt/live/#{server_name}/privkey.pem"
|
|
||||||
notifies :reload, 'service[nginx]', :delayed
|
|
||||||
end
|
|
||||||
|
|
||||||
nginx_site server_name do
|
|
||||||
action :enable
|
|
||||||
end
|
|
||||||
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
# Generated by Chef
|
|
||||||
upstream _sockethub {
|
upstream _sockethub {
|
||||||
server localhost:<%= @sockethub_port %>;
|
server <%= @upstream_host %>:<%= @upstream_port %>;
|
||||||
}
|
}
|
||||||
|
|
||||||
map $http_upgrade $connection_upgrade {
|
map $http_upgrade $connection_upgrade {
|
||||||
@@ -9,34 +8,25 @@ map $http_upgrade $connection_upgrade {
|
|||||||
}
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
<% if File.exist?(@ssl_cert) && File.exist?(@ssl_key) -%>
|
server_name <%= @domain %>;
|
||||||
listen <%= @sockethub_external_port %> ssl http2;
|
listen <%= "#{node['openresty']['listen_ip']}:" if node['openresty']['listen_ip'] %>443 ssl http2;
|
||||||
add_header Strict-Transport-Security "max-age=15768000";
|
listen <%= "[#{node['openresty']['listen_ipv6']}]" %>:443 ssl http2;
|
||||||
<% else -%>
|
|
||||||
listen <%= @sockethub_external_port %>;
|
|
||||||
<% end -%>
|
|
||||||
|
|
||||||
server_name <%= @server_name %>;
|
access_log "/var/log/nginx/<%= @domain %>.access.log" json;
|
||||||
|
error_log "/var/log/nginx/<%= @domain %>.error.log";
|
||||||
|
|
||||||
access_log <%= node[:nginx][:log_dir] %>/sockethub.access.log json;
|
ssl_certificate <%= @ssl_cert %>;
|
||||||
error_log <%= node[:nginx][:log_dir] %>/sockethub.error.log warn;
|
ssl_certificate_key <%= @ssl_key %>;
|
||||||
|
|
||||||
# We might need real ETags, disable those for now
|
|
||||||
gzip off;
|
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
# Increase number of buffers. Default is 8
|
proxy_set_header Host $host;
|
||||||
proxy_buffers 1024 8k;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_pass http://_sockethub;
|
proxy_pass http://_sockethub;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
# Enable WebSockets
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection $connection_upgrade;
|
proxy_set_header Connection $connection_upgrade;
|
||||||
}
|
proxy_read_timeout 300s;
|
||||||
|
}
|
||||||
<% if File.exist?(@ssl_cert) && File.exist?(@ssl_key) -%>
|
|
||||||
ssl_certificate <%= @ssl_cert %>;
|
|
||||||
ssl_certificate_key <%= @ssl_key %>;
|
|
||||||
<% end -%>
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"examples": false,
|
||||||
|
"logging": {
|
||||||
|
"level": "<%= @log_level %>",
|
||||||
|
"file": ""
|
||||||
|
},
|
||||||
|
"public": {
|
||||||
|
"protocol": "https",
|
||||||
|
"host": "<%= @domain %>",
|
||||||
|
"port": 443,
|
||||||
|
"path": "/"
|
||||||
|
},
|
||||||
|
"redis": {
|
||||||
|
"url": "redis://127.0.0.1:6379/0"
|
||||||
|
},
|
||||||
|
"sockethub": {
|
||||||
|
"port": <%= @port.to_i %>,
|
||||||
|
"host": "0.0.0.0",
|
||||||
|
"path": "/sockethub",
|
||||||
|
"trustProxy": 1
|
||||||
|
},
|
||||||
|
"credentialCheck": {
|
||||||
|
"reconnectIpSource": "proxy",
|
||||||
|
"proxyHeader": "x-forwarded-for"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
|
|
||||||
set -euf -o pipefail
|
|
||||||
|
|
||||||
# ************** USAGE **************
|
|
||||||
#
|
|
||||||
# Example usage (with this hook file saved in /root/):
|
|
||||||
#
|
|
||||||
# sudo su -
|
|
||||||
# certbot certonly --manual --preferred-challenges dns --manual-public-ip-logging-ok --agree-tos -d "5apps.com" -d muc.5apps.com -d "xmpp.5apps.com" \
|
|
||||||
# --manual-auth-hook "/root/letsencrypt_hook.sh auth" --manual-cleanup-hook "/root/letsencrypt_hook.sh cleanup"
|
|
||||||
#
|
|
||||||
# This hook requires configuration, continue reading.
|
|
||||||
#
|
|
||||||
# ************** CONFIGURATION **************
|
|
||||||
#
|
|
||||||
# GANDI_API_KEY: Your Gandi Live API key
|
|
||||||
#
|
|
||||||
# PROVIDER_UPDATE_DELAY:
|
|
||||||
# How many seconds to wait after updating your DNS records. This may be required,
|
|
||||||
# depending on how slow your DNS host is to begin serving new DNS records after updating
|
|
||||||
# them via the API. 30 seconds is a safe default, but some providers can be very slow
|
|
||||||
# (e.g. Linode).
|
|
||||||
#
|
|
||||||
# Defaults to 30 seconds.
|
|
||||||
#
|
|
||||||
GANDI_API_KEY="<%= @gandi_api_key %>"
|
|
||||||
PROVIDER_UPDATE_DELAY=30
|
|
||||||
|
|
||||||
regex='.*\.(.*\..*)'
|
|
||||||
if [[ $CERTBOT_DOMAIN =~ $regex ]]
|
|
||||||
then
|
|
||||||
DOMAIN="${BASH_REMATCH[1]}"
|
|
||||||
else
|
|
||||||
DOMAIN="${CERTBOT_DOMAIN}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# To be invoked via Certbot's --manual-auth-hook
|
|
||||||
function auth {
|
|
||||||
curl -s -D- -H "Content-Type: application/json" \
|
|
||||||
-H "X-Api-Key: ${GANDI_API_KEY}" \
|
|
||||||
-d "{\"rrset_name\": \"_acme-challenge.${CERTBOT_DOMAIN}.\",
|
|
||||||
\"rrset_type\": \"TXT\",
|
|
||||||
\"rrset_ttl\": 3600,
|
|
||||||
\"rrset_values\": [\"${CERTBOT_VALIDATION}\"]}" \
|
|
||||||
"https://dns.api.gandi.net/api/v5/domains/${DOMAIN}/records"
|
|
||||||
|
|
||||||
|
|
||||||
sleep ${PROVIDER_UPDATE_DELAY}
|
|
||||||
}
|
|
||||||
|
|
||||||
# To be invoked via Certbot's --manual-cleanup-hook
|
|
||||||
function cleanup {
|
|
||||||
curl -s -X DELETE -H "Content-Type: application/json" \
|
|
||||||
-H "X-Api-Key: ${GANDI_API_KEY}" \
|
|
||||||
https://dns.api.gandi.net/api/v5/domains/${DOMAIN}/records/_acme-challenge.${CERTBOT_DOMAIN}./TXT
|
|
||||||
}
|
|
||||||
|
|
||||||
HANDLER=$1; shift;
|
|
||||||
if [ -n "$(type -t $HANDLER)" ] && [ "$(type -t $HANDLER)" = function ]; then
|
|
||||||
$HANDLER "$@"
|
|
||||||
fi
|
|
||||||
Reference in New Issue
Block a user