Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
Acme.Sh
Commits
768e00ff
Commit
768e00ff
authored
Nov 30, 2020
by
jakelamotta
Browse files
Merge remote-tracking branch 'upstream/dev' into dev
parents
d9dec6fe
be067466
Changes
5
Hide whitespace changes
Inline
Side-by-side
acme.sh
View file @
768e00ff
...
@@ -1722,6 +1722,14 @@ _mktemp() {
...
@@ -1722,6 +1722,14 @@ _mktemp() {
_err
"Can not create temp file."
_err
"Can not create temp file."
}
}
#clear all the https envs to cause _inithttp() to run next time.
_resethttp
()
{
__HTTP_INITIALIZED
=
""
_ACME_CURL
=
""
_ACME_WGET
=
""
ACME_HTTP_NO_REDIRECTS
=
""
}
_inithttp
()
{
_inithttp
()
{
if
[
-z
"
$HTTP_HEADER
"
]
||
!
touch
"
$HTTP_HEADER
"
;
then
if
[
-z
"
$HTTP_HEADER
"
]
||
!
touch
"
$HTTP_HEADER
"
;
then
...
@@ -1737,7 +1745,10 @@ _inithttp() {
...
@@ -1737,7 +1745,10 @@ _inithttp() {
fi
fi
if
[
-z
"
$_ACME_CURL
"
]
&&
_exists
"curl"
;
then
if
[
-z
"
$_ACME_CURL
"
]
&&
_exists
"curl"
;
then
_ACME_CURL
=
"curl -L --silent --dump-header
$HTTP_HEADER
"
_ACME_CURL
=
"curl --silent --dump-header
$HTTP_HEADER
"
if
[
-z
"
$ACME_HTTP_NO_REDIRECTS
"
]
;
then
_ACME_CURL
=
"
$_ACME_CURL
-L "
fi
if
[
"
$DEBUG
"
]
&&
[
"
$DEBUG
"
-ge
"2"
]
;
then
if
[
"
$DEBUG
"
]
&&
[
"
$DEBUG
"
-ge
"2"
]
;
then
_CURL_DUMP
=
"
$(
_mktemp
)
"
_CURL_DUMP
=
"
$(
_mktemp
)
"
_ACME_CURL
=
"
$_ACME_CURL
--trace-ascii
$_CURL_DUMP
"
_ACME_CURL
=
"
$_ACME_CURL
--trace-ascii
$_CURL_DUMP
"
...
@@ -1756,6 +1767,9 @@ _inithttp() {
...
@@ -1756,6 +1767,9 @@ _inithttp() {
if
[
-z
"
$_ACME_WGET
"
]
&&
_exists
"wget"
;
then
if
[
-z
"
$_ACME_WGET
"
]
&&
_exists
"wget"
;
then
_ACME_WGET
=
"wget -q"
_ACME_WGET
=
"wget -q"
if
[
"
$ACME_HTTP_NO_REDIRECTS
"
]
;
then
_ACME_WGET
=
"
$_ACME_WGET
--max-redirect 0 "
fi
if
[
"
$DEBUG
"
]
&&
[
"
$DEBUG
"
-ge
"2"
]
;
then
if
[
"
$DEBUG
"
]
&&
[
"
$DEBUG
"
-ge
"2"
]
;
then
_ACME_WGET
=
"
$_ACME_WGET
-d "
_ACME_WGET
=
"
$_ACME_WGET
-d "
fi
fi
...
@@ -6649,8 +6663,8 @@ _checkSudo() {
...
@@ -6649,8 +6663,8 @@ _checkSudo() {
return
0
return
0
fi
fi
if
[
-n
"
$SUDO_COMMAND
"
]
;
then
if
[
-n
"
$SUDO_COMMAND
"
]
;
then
#it's a normal user doing "sudo su", or `sudo -i` or `sudo -s`
#it's a normal user doing "sudo su", or `sudo -i` or `sudo -s`
, or `sudo su acmeuser1`
_endswith
"
$SUDO_COMMAND
"
/bin/su
||
grep
"^
$SUDO_COMMAND
\$
"
/etc/shells
>
/dev/null 2>&1
_endswith
"
$SUDO_COMMAND
"
/bin/su
||
_contains
"
$SUDO_COMMAND
"
"/bin/su "
||
grep
"^
$SUDO_COMMAND
\$
"
/etc/shells
>
/dev/null 2>&1
return
$?
return
$?
fi
fi
#otherwise
#otherwise
...
...
deploy/cleverreach.sh
0 → 100644
View file @
768e00ff
#!/usr/bin/env sh
# Here is the script to deploy the cert to your CleverReach Account using the CleverReach REST API.
# Your OAuth needs the right scope, please contact CleverReach support for that.
#
# Written by Jan-Philipp Benecke <github@bnck.me>
# Public domain, 2020
#
# Following environment variables must be set:
#
#export DEPLOY_CLEVERREACH_CLIENT_ID=myid
#export DEPLOY_CLEVERREACH_CLIENT_SECRET=mysecret
cleverreach_deploy
()
{
_cdomain
=
"
$1
"
_ckey
=
"
$2
"
_ccert
=
"
$3
"
_cca
=
"
$4
"
_cfullchain
=
"
$5
"
_debug _cdomain
"
$_cdomain
"
_debug _ckey
"
$_ckey
"
_debug _ccert
"
$_ccert
"
_debug _cca
"
$_cca
"
_debug _cfullchain
"
$_cfullchain
"
_getdeployconf DEPLOY_CLEVERREACH_CLIENT_ID
_getdeployconf DEPLOY_CLEVERREACH_CLIENT_SECRET
if
[
-z
"
${
DEPLOY_CLEVERREACH_CLIENT_ID
}
"
]
;
then
_err
"CleverReach Client ID is not found, please define DEPLOY_CLEVERREACH_CLIENT_ID."
return
1
fi
if
[
-z
"
${
DEPLOY_CLEVERREACH_CLIENT_SECRET
}
"
]
;
then
_err
"CleverReach client secret is not found, please define DEPLOY_CLEVERREACH_CLIENT_SECRET."
return
1
fi
_savedeployconf DEPLOY_CLEVERREACH_CLIENT_ID
"
${
DEPLOY_CLEVERREACH_CLIENT_ID
}
"
_savedeployconf DEPLOY_CLEVERREACH_CLIENT_SECRET
"
${
DEPLOY_CLEVERREACH_CLIENT_SECRET
}
"
_info
"Obtaining a CleverReach access token"
_data
=
"{
\"
grant_type
\"
:
\"
client_credentials
\"
,
\"
client_id
\"
:
\"
${
DEPLOY_CLEVERREACH_CLIENT_ID
}
\"
,
\"
client_secret
\"
:
\"
${
DEPLOY_CLEVERREACH_CLIENT_SECRET
}
\"
}"
_auth_result
=
"
$(
_post
"
$_data
"
"https://rest.cleverreach.com/oauth/token.php"
""
"POST"
"application/json"
)
"
_debug _data
"
$_data
"
_debug _auth_result
"
$_auth_result
"
_regex
=
".*
\"
access_token
\"
:
\"\(
[-._0-9A-Za-z]*
\)\"
.*$"
_debug _regex
"
$_regex
"
_access_token
=
$(
echo
"
$_auth_result
"
| _json_decode |
sed
-n
"s/
$_regex
/
\1
/p"
)
_info
"Uploading certificate and key to CleverReach"
_certData
=
"{
\"
cert
\"
:
\"
$(
_json_encode <
"
$_cfullchain
"
)
\"
,
\"
key
\"
:
\"
$(
_json_encode <
"
$_ckey
"
)
\"
}"
export
_H1
=
"Authorization: Bearer
${
_access_token
}
"
_add_cert_result
=
"
$(
_post
"
$_certData
"
"https://rest.cleverreach.com/v3/ssl"
""
"POST"
"application/json"
)
"
_debug
"Destroying token at CleverReach"
_post
""
"https://rest.cleverreach.com/v3/oauth/token.json"
""
"DELETE"
"application/json"
if
!
echo
"
$_add_cert_result
"
|
grep
'"error":'
>
/dev/null
;
then
_info
"Uploaded certificate successfully"
return
0
else
_debug _add_cert_result
"
$_add_cert_result
"
_err
"Unable to update certificate"
return
1
fi
}
deploy/fritzbox.sh
View file @
768e00ff
...
@@ -28,9 +28,11 @@ fritzbox_deploy() {
...
@@ -28,9 +28,11 @@ fritzbox_deploy() {
_debug _cfullchain
"
$_cfullchain
"
_debug _cfullchain
"
$_cfullchain
"
if
!
_exists iconv
;
then
if
!
_exists iconv
;
then
if
!
_exists perl
;
then
if
!
_exists uconv
;
then
_err
"iconv or perl not found"
if
!
_exists perl
;
then
return
1
_err
"iconv or uconv or perl not found"
return
1
fi
fi
fi
fi
fi
...
@@ -65,6 +67,8 @@ fritzbox_deploy() {
...
@@ -65,6 +67,8 @@ fritzbox_deploy() {
_fritzbox_challenge
=
"
$(
_get
"
${
_fritzbox_url
}
/login_sid.lua"
|
sed
-e
's/^.*<Challenge>//'
-e
's/<\/Challenge>.*$//'
)
"
_fritzbox_challenge
=
"
$(
_get
"
${
_fritzbox_url
}
/login_sid.lua"
|
sed
-e
's/^.*<Challenge>//'
-e
's/<\/Challenge>.*$//'
)
"
if
_exists iconv
;
then
if
_exists iconv
;
then
_fritzbox_hash
=
"
$(
printf
"%s-%s"
"
${
_fritzbox_challenge
}
"
"
${
_fritzbox_password
}
"
| iconv
-f
ASCII
-t
UTF16LE | _digest md5 hex
)
"
_fritzbox_hash
=
"
$(
printf
"%s-%s"
"
${
_fritzbox_challenge
}
"
"
${
_fritzbox_password
}
"
| iconv
-f
ASCII
-t
UTF16LE | _digest md5 hex
)
"
elif
_exists uconv
;
then
_fritzbox_hash
=
"
$(
printf
"%s-%s"
"
${
_fritzbox_challenge
}
"
"
${
_fritzbox_password
}
"
| uconv
-f
ASCII
-t
UTF16LE | _digest md5 hex
)
"
else
else
_fritzbox_hash
=
"
$(
printf
"%s-%s"
"
${
_fritzbox_challenge
}
"
"
${
_fritzbox_password
}
"
| perl
-p
-e
'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";'
| _digest md5 hex
)
"
_fritzbox_hash
=
"
$(
printf
"%s-%s"
"
${
_fritzbox_challenge
}
"
"
${
_fritzbox_password
}
"
| perl
-p
-e
'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";'
| _digest md5 hex
)
"
fi
fi
...
...
dnsapi/dns_desec.sh
View file @
768e00ff
...
@@ -61,7 +61,7 @@ dns_desec_add() {
...
@@ -61,7 +61,7 @@ dns_desec_add() {
fi
fi
_debug txtvalues
"
$txtvalues
"
_debug txtvalues
"
$txtvalues
"
_info
"Adding record"
_info
"Adding record"
body
=
"[{
\"
subname
\"
:
\"
$_sub_domain
\"
,
\"
type
\"
:
\"
TXT
\"
,
\"
records
\"
:[
$txtvalues
],
\"
ttl
\"
:
6
0}]"
body
=
"[{
\"
subname
\"
:
\"
$_sub_domain
\"
,
\"
type
\"
:
\"
TXT
\"
,
\"
records
\"
:[
$txtvalues
],
\"
ttl
\"
:
360
0}]"
if
_desec_rest PUT
"
$REST_API
/
$DEDYN_NAME
/rrsets/"
"
$body
"
;
then
if
_desec_rest PUT
"
$REST_API
/
$DEDYN_NAME
/rrsets/"
"
$body
"
;
then
if
_contains
"
$response
"
"
$txtvalue
"
;
then
if
_contains
"
$response
"
"
$txtvalue
"
;
then
...
@@ -130,7 +130,7 @@ dns_desec_rm() {
...
@@ -130,7 +130,7 @@ dns_desec_rm() {
_debug txtvalues
"
$txtvalues
"
_debug txtvalues
"
$txtvalues
"
_info
"Deleting record"
_info
"Deleting record"
body
=
"[{
\"
subname
\"
:
\"
$_sub_domain
\"
,
\"
type
\"
:
\"
TXT
\"
,
\"
records
\"
:[
$txtvalues
],
\"
ttl
\"
:
6
0}]"
body
=
"[{
\"
subname
\"
:
\"
$_sub_domain
\"
,
\"
type
\"
:
\"
TXT
\"
,
\"
records
\"
:[
$txtvalues
],
\"
ttl
\"
:
360
0}]"
_desec_rest PUT
"
$REST_API
/
$DEDYN_NAME
/rrsets/"
"
$body
"
_desec_rest PUT
"
$REST_API
/
$DEDYN_NAME
/rrsets/"
"
$body
"
if
[
"
$_code
"
=
"200"
]
;
then
if
[
"
$_code
"
=
"200"
]
;
then
_info
"Deleted, OK"
_info
"Deleted, OK"
...
...
dnsapi/dns_huaweicloud.sh
0 → 100644
View file @
768e00ff
#!/usr/bin/env sh
# HUAWEICLOUD_Username
# HUAWEICLOUD_Password
# HUAWEICLOUD_ProjectID
iam_api
=
"https://iam.myhuaweicloud.com"
dns_api
=
"https://dns.ap-southeast-1.myhuaweicloud.com"
######## Public functions #####################
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record
#
# Ref: https://support.huaweicloud.com/intl/zh-cn/api-dns/zh-cn_topic_0132421999.html
#
dns_huaweicloud_add
()
{
fulldomain
=
$1
txtvalue
=
$2
HUAWEICLOUD_Username
=
"
${
HUAWEICLOUD_Username
:-
$(
_readaccountconf_mutable HUAWEICLOUD_Username
)
}
"
HUAWEICLOUD_Password
=
"
${
HUAWEICLOUD_Password
:-
$(
_readaccountconf_mutable HUAWEICLOUD_Password
)
}
"
HUAWEICLOUD_ProjectID
=
"
${
HUAWEICLOUD_ProjectID
:-
$(
_readaccountconf_mutable HUAWEICLOUD_ProjectID
)
}
"
# Check information
if
[
-z
"
${
HUAWEICLOUD_Username
}
"
]
||
[
-z
"
${
HUAWEICLOUD_Password
}
"
]
||
[
-z
"
${
HUAWEICLOUD_ProjectID
}
"
]
;
then
_err
"Not enough information provided to dns_huaweicloud!"
return
1
fi
token
=
"
$(
_get_token
"
${
HUAWEICLOUD_Username
}
"
"
${
HUAWEICLOUD_Password
}
"
"
${
HUAWEICLOUD_ProjectID
}
"
)
"
_debug2
"
${
token
}
"
zoneid
=
"
$(
_get_zoneid
"
${
token
}
"
"
${
fulldomain
}
"
)
"
_debug
"
${
zoneid
}
"
_debug
"Adding Record"
_add_record
"
${
token
}
"
"
${
fulldomain
}
"
"
${
txtvalue
}
"
ret
=
"
$?
"
if
[
"
${
ret
}
"
!=
"0"
]
;
then
_err
"dns_huaweicloud: Error adding record."
return
1
fi
# Do saving work if all succeeded
_saveaccountconf_mutable HUAWEICLOUD_Username
"
${
HUAWEICLOUD_Username
}
"
_saveaccountconf_mutable HUAWEICLOUD_Password
"
${
HUAWEICLOUD_Password
}
"
_saveaccountconf_mutable HUAWEICLOUD_ProjectID
"
${
HUAWEICLOUD_ProjectID
}
"
return
0
}
# Usage: fulldomain txtvalue
# Used to remove the txt record after validation
#
# Ref: https://support.huaweicloud.com/intl/zh-cn/api-dns/dns_api_64005.html
#
dns_huaweicloud_rm
()
{
fulldomain
=
$1
txtvalue
=
$2
HUAWEICLOUD_Username
=
"
${
HUAWEICLOUD_Username
:-
$(
_readaccountconf_mutable HUAWEICLOUD_Username
)
}
"
HUAWEICLOUD_Password
=
"
${
HUAWEICLOUD_Password
:-
$(
_readaccountconf_mutable HUAWEICLOUD_Password
)
}
"
HUAWEICLOUD_ProjectID
=
"
${
HUAWEICLOUD_ProjectID
:-
$(
_readaccountconf_mutable HUAWEICLOUD_ProjectID
)
}
"
# Check information
if
[
-z
"
${
HUAWEICLOUD_Username
}
"
]
||
[
-z
"
${
HUAWEICLOUD_Password
}
"
]
||
[
-z
"
${
HUAWEICLOUD_ProjectID
}
"
]
;
then
_err
"Not enough information provided to dns_huaweicloud!"
return
1
fi
token
=
"
$(
_get_token
"
${
HUAWEICLOUD_Username
}
"
"
${
HUAWEICLOUD_Password
}
"
"
${
HUAWEICLOUD_ProjectID
}
"
)
"
_debug2
"
${
token
}
"
zoneid
=
"
$(
_get_zoneid
"
${
token
}
"
"
${
fulldomain
}
"
)
"
_debug
"
${
zoneid
}
"
record_id
=
"
$(
_get_recordset_id
"
${
token
}
"
"
${
fulldomain
}
"
"
${
zoneid
}
"
)
"
_debug
"Record Set ID is:
${
record_id
}
"
# Remove all records
# Therotically HuaweiCloud does not allow more than one record set
# But remove them recurringly to increase robusty
while
[
"
${
record_id
}
"
!=
"0"
]
;
do
_debug
"Removing Record"
_rm_record
"
${
token
}
"
"
${
zoneid
}
"
"
${
record_id
}
"
record_id
=
"
$(
_get_recordset_id
"
${
token
}
"
"
${
fulldomain
}
"
"
${
zoneid
}
"
)
"
done
return
0
}
################### Private functions below ##################################
# _get_zoneid
#
# _token=$1
# _domain_string=$2
#
# printf "%s" "${_zoneid}"
_get_zoneid
()
{
_token
=
$1
_domain_string
=
$2
export
_H1
=
"X-Auth-Token:
${
_token
}
"
i
=
1
while
true
;
do
h
=
$(
printf
"%s"
"
${
_domain_string
}
"
|
cut
-d
.
-f
$i
-100
)
if
[
-z
"
$h
"
]
;
then
#not valid
return
1
fi
_debug
"
$h
"
response
=
$(
_get
"
${
dns_api
}
/v2/zones?name=
${
h
}
"
)
if
_contains
"
${
response
}
"
"id"
;
then
_debug
"Get Zone ID Success."
_zoneid
=
$(
echo
"
${
response
}
"
| _egrep_o
"
\"
id
\"
: *
\"
[^
\"
]*
\"
"
|
cut
-d
:
-f
2 |
tr
-d
\"
|
tr
-d
" "
)
printf
"%s"
"
${
_zoneid
}
"
return
0
fi
i
=
$(
_math
"
$i
"
+ 1
)
done
return
1
}
_get_recordset_id
()
{
_token
=
$1
_domain
=
$2
_zoneid
=
$3
export
_H1
=
"X-Auth-Token:
${
_token
}
"
response
=
$(
_get
"
${
dns_api
}
/v2/zones/
${
_zoneid
}
/recordsets?name=
${
_domain
}
"
)
if
_contains
"
${
response
}
"
"id"
;
then
_id
=
"
$(
echo
"
${
response
}
"
| _egrep_o
"
\"
id
\"
: *
\"
[^
\"
]*
\"
"
|
cut
-d
:
-f
2 |
tr
-d
\"
|
tr
-d
" "
)
"
printf
"%s"
"
${
_id
}
"
return
0
fi
printf
"%s"
"0"
return
1
}
_add_record
()
{
_token
=
$1
_domain
=
$2
_txtvalue
=
$3
# Get Existing Records
export
_H1
=
"X-Auth-Token:
${
_token
}
"
response
=
$(
_get
"
${
dns_api
}
/v2/zones/
${
zoneid
}
/recordsets?name=
${
_domain
}
"
)
_debug2
"
${
response
}
"
_exist_record
=
$(
echo
"
${
response
}
"
| _egrep_o
'"records":[^]]*'
|
sed
's/\"records\"\:\[//g'
)
_debug
"
${
_exist_record
}
"
# Check if record exist
# Generate body data
if
[
-z
"
${
_exist_record
}
"
]
;
then
_post_body
=
"{
\"
name
\"
:
\"
${
_domain
}
.
\"
,
\"
description
\"
:
\"
ACME Challenge
\"
,
\"
type
\"
:
\"
TXT
\"
,
\"
ttl
\"
: 1,
\"
records
\"
: [
\"\\\"
${
_txtvalue
}
\\\"\"
]
}"
else
_post_body
=
"{
\"
name
\"
:
\"
${
_domain
}
.
\"
,
\"
description
\"
:
\"
ACME Challenge
\"
,
\"
type
\"
:
\"
TXT
\"
,
\"
ttl
\"
: 1,
\"
records
\"
: [
${
_exist_record
}
,
\"\\\"
${
_txtvalue
}
\\\"\"
]
}"
fi
_record_id
=
"
$(
_get_recordset_id
"
${
_token
}
"
"
${
_domain
}
"
"
${
zoneid
}
"
)
"
_debug
"Record Set ID is:
${
_record_id
}
"
# Remove all records
while
[
"
${
_record_id
}
"
!=
"0"
]
;
do
_debug
"Removing Record"
_rm_record
"
${
_token
}
"
"
${
zoneid
}
"
"
${
_record_id
}
"
_record_id
=
"
$(
_get_recordset_id
"
${
_token
}
"
"
${
_domain
}
"
"
${
zoneid
}
"
)
"
done
# Add brand new records with all old and new records
export
_H2
=
"Content-Type: application/json"
export
_H1
=
"X-Auth-Token:
${
_token
}
"
_debug2
"
${
_post_body
}
"
_post
"
${
_post_body
}
"
"
${
dns_api
}
/v2/zones/
${
zoneid
}
/recordsets"
>
/dev/null
_code
=
"
$(
grep
"^HTTP"
"
$HTTP_HEADER
"
| _tail_n 1 |
cut
-d
" "
-f
2 |
tr
-d
"
\\
r
\\
n"
)
"
if
[
"
$_code
"
!=
"202"
]
;
then
_err
"dns_huaweicloud: http code
${
_code
}
"
return
1
fi
return
0
}
# _rm_record $token $zoneid $recordid
# assume ${dns_api} exist
# no output
# return 0
_rm_record
()
{
_token
=
$1
_zone_id
=
$2
_record_id
=
$3
export
_H2
=
"Content-Type: application/json"
export
_H1
=
"X-Auth-Token:
${
_token
}
"
_post
""
"
${
dns_api
}
/v2/zones/
${
_zone_id
}
/recordsets/
${
_record_id
}
"
false
"DELETE"
>
/dev/null
return
$?
}
_get_token
()
{
_username
=
$1
_password
=
$2
_project
=
$3
_debug
"Getting Token"
body
=
"{
\"
auth
\"
: {
\"
identity
\"
: {
\"
methods
\"
: [
\"
password
\"
],
\"
password
\"
: {
\"
user
\"
: {
\"
name
\"
:
\"
${
_username
}
\"
,
\"
password
\"
:
\"
${
_password
}
\"
,
\"
domain
\"
: {
\"
name
\"
:
\"
${
_username
}
\"
}
}
}
},
\"
scope
\"
: {
\"
project
\"
: {
\"
id
\"
:
\"
${
_project
}
\"
}
}
}
}"
export
_H1
=
"Content-Type: application/json;charset=utf8"
_post
"
${
body
}
"
"
${
iam_api
}
/v3/auth/tokens"
>
/dev/null
_code
=
$(
grep
"^HTTP"
"
$HTTP_HEADER
"
| _tail_n 1 |
cut
-d
" "
-f
2 |
tr
-d
"
\\
r
\\
n"
)
_token
=
$(
grep
"^X-Subject-Token"
"
$HTTP_HEADER
"
|
cut
-d
" "
-f
2-
)
_debug2
"
${
_code
}
"
printf
"%s"
"
${
_token
}
"
return
0
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment