0f36bb1130
An $a without quotes is not putting quotes around expanded characters. The quotes around the server reload command get lost in the process.
1289 lines
31 KiB
Bash
Executable File
1289 lines
31 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
VER=1.1.8
|
|
PROJECT="https://github.com/Neilpang/le"
|
|
|
|
DEFAULT_CA="https://acme-v01.api.letsencrypt.org"
|
|
DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf"
|
|
|
|
STAGE_CA="https://acme-staging.api.letsencrypt.org"
|
|
|
|
VTYPE_HTTP="http-01"
|
|
VTYPE_DNS="dns-01"
|
|
|
|
if [ -z "$AGREEMENT" ] ; then
|
|
AGREEMENT="$DEFAULT_AGREEMENT"
|
|
fi
|
|
|
|
_debug() {
|
|
|
|
if [ -z "$DEBUG" ] ; then
|
|
return
|
|
fi
|
|
|
|
if [ -z "$2" ] ; then
|
|
echo $1
|
|
else
|
|
echo "$1"="$2"
|
|
fi
|
|
}
|
|
|
|
_info() {
|
|
if [ -z "$2" ] ; then
|
|
echo "$1"
|
|
else
|
|
echo "$1"="$2"
|
|
fi
|
|
}
|
|
|
|
_err() {
|
|
if [ -z "$2" ] ; then
|
|
echo "$1" >&2
|
|
else
|
|
echo "$1"="$2" >&2
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
_h2b() {
|
|
hex=$(cat)
|
|
i=1
|
|
j=2
|
|
while [ '1' ] ; do
|
|
h=$(printf $hex | cut -c $i-$j)
|
|
if [ -z "$h" ] ; then
|
|
break;
|
|
fi
|
|
printf "\x$h"
|
|
let "i+=2"
|
|
let "j+=2"
|
|
done
|
|
}
|
|
|
|
_base64() {
|
|
openssl base64 -e | tr -d '\n'
|
|
}
|
|
|
|
#domain [2048]
|
|
createAccountKey() {
|
|
_info "Creating account key"
|
|
if [ -z "$1" ] ; then
|
|
echo Usage: createAccountKey account-domain [2048]
|
|
return
|
|
fi
|
|
|
|
account=$1
|
|
length=$2
|
|
|
|
if [[ "$length" == "ec-"* ]] ; then
|
|
length=2048
|
|
fi
|
|
|
|
if [ -z "$2" ] ; then
|
|
_info "Use default length 2048"
|
|
length=2048
|
|
fi
|
|
_initpath
|
|
|
|
if [ -f "$ACCOUNT_KEY_PATH" ] ; then
|
|
_info "Account key exists, skip"
|
|
return
|
|
else
|
|
#generate account key
|
|
openssl genrsa $length > "$ACCOUNT_KEY_PATH"
|
|
fi
|
|
|
|
}
|
|
|
|
#domain length
|
|
createDomainKey() {
|
|
_info "Creating domain key"
|
|
if [ -z "$1" ] ; then
|
|
echo Usage: createDomainKey domain [2048]
|
|
return
|
|
fi
|
|
|
|
domain=$1
|
|
length=$2
|
|
isec=""
|
|
if [[ "$length" == "ec-"* ]] ; then
|
|
isec="1"
|
|
length=$(printf $length | cut -d '-' -f 2-100)
|
|
eccname="$length"
|
|
fi
|
|
|
|
if [ -z "$length" ] ; then
|
|
if [ "$isec" ] ; then
|
|
length=256
|
|
else
|
|
length=2048
|
|
fi
|
|
fi
|
|
_info "Use length $length"
|
|
|
|
if [ "$isec" ] ; then
|
|
if [ "$length" == "256" ] ; then
|
|
eccname="prime256v1"
|
|
fi
|
|
if [ "$length" == "384" ] ; then
|
|
eccname="secp384r1"
|
|
fi
|
|
if [ "$length" == "521" ] ; then
|
|
eccname="secp521r1"
|
|
fi
|
|
_info "Using ec name: $eccname"
|
|
fi
|
|
|
|
_initpath $domain
|
|
|
|
if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then
|
|
#generate account key
|
|
if [ "$isec" ] ; then
|
|
openssl ecparam -name $eccname -genkey 2>/dev/null > "$CERT_KEY_PATH"
|
|
else
|
|
openssl genrsa $length 2>/dev/null > "$CERT_KEY_PATH"
|
|
fi
|
|
else
|
|
if [ "$IS_RENEW" ] ; then
|
|
_info "Domain key exists, skip"
|
|
return 0
|
|
else
|
|
_err "Domain key exists, do you want to overwrite the key?"
|
|
_err "Set FORCE=1, and try again."
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
}
|
|
|
|
# domain domainlist
|
|
createCSR() {
|
|
_info "Creating csr"
|
|
if [ -z "$1" ] ; then
|
|
echo Usage: $0 domain [domainlist]
|
|
return
|
|
fi
|
|
domain=$1
|
|
_initpath $domain
|
|
|
|
domainlist=$2
|
|
|
|
if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && ! [ "$FORCE" ]; then
|
|
_info "CSR exists, skip"
|
|
return
|
|
fi
|
|
|
|
if [ -z "$domainlist" ] ; then
|
|
#single domain
|
|
_info "Single domain" $domain
|
|
openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" > "$CSR_PATH"
|
|
else
|
|
alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")"
|
|
#multi
|
|
_info "Multi domain" "$alt"
|
|
printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n[SAN]\nsubjectAltName=$alt" > "$DOMAIN_SSL_CONF"
|
|
openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" -reqexts SAN -config "$DOMAIN_SSL_CONF" -out "$CSR_PATH"
|
|
fi
|
|
|
|
}
|
|
|
|
_b64() {
|
|
__n=$(cat)
|
|
echo $__n | tr '/+' '_-' | tr -d '= '
|
|
}
|
|
|
|
_time2str() {
|
|
#BSD
|
|
if date -u -d@$1 2>/dev/null ; then
|
|
return
|
|
fi
|
|
|
|
#Linux
|
|
if date -u -r $1 2>/dev/null ; then
|
|
return
|
|
fi
|
|
|
|
}
|
|
|
|
_send_signed_request() {
|
|
url=$1
|
|
payload=$2
|
|
needbase64=$3
|
|
|
|
_debug url $url
|
|
_debug payload "$payload"
|
|
|
|
CURL_HEADER="$LE_WORKING_DIR/curl.header"
|
|
dp="$LE_WORKING_DIR/curl.dump"
|
|
CURL="curl --silent --dump-header $CURL_HEADER "
|
|
if [ "$DEBUG" ] ; then
|
|
CURL="$CURL --trace-ascii $dp "
|
|
fi
|
|
payload64=$(echo -n $payload | _base64 | _b64)
|
|
_debug payload64 $payload64
|
|
|
|
nonceurl="$API/directory"
|
|
nonce="$($CURL -I $nonceurl | grep -o "^Replay-Nonce:.*$" | tr -d "\r\n" | cut -d ' ' -f 2)"
|
|
|
|
_debug nonce "$nonce"
|
|
|
|
protected="$(printf "$HEADERPLACE" | sed "s/NONCE/$nonce/" )"
|
|
_debug protected "$protected"
|
|
|
|
protected64="$(printf "$protected" | _base64 | _b64)"
|
|
_debug protected64 "$protected64"
|
|
|
|
sig=$(echo -n "$protected64.$payload64" | openssl dgst -sha256 -sign $ACCOUNT_KEY_PATH | _base64 | _b64)
|
|
_debug sig "$sig"
|
|
|
|
body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
|
|
_debug body "$body"
|
|
|
|
if [ "$needbase64" ] ; then
|
|
response="$($CURL -X POST --data "$body" $url | _base64)"
|
|
else
|
|
response="$($CURL -X POST --data "$body" $url)"
|
|
fi
|
|
|
|
responseHeaders="$(cat $CURL_HEADER)"
|
|
|
|
_debug responseHeaders "$responseHeaders"
|
|
_debug response "$response"
|
|
code="$(grep ^HTTP $CURL_HEADER | tail -1 | cut -d " " -f 2 | tr -d "\r\n" )"
|
|
_debug code $code
|
|
|
|
}
|
|
|
|
_get() {
|
|
url="$1"
|
|
_debug url $url
|
|
response="$(curl --silent $url)"
|
|
ret=$?
|
|
_debug response "$response"
|
|
code="$(echo $response | grep -o '"status":[0-9]\+' | cut -d : -f 2)"
|
|
_debug code $code
|
|
return $ret
|
|
}
|
|
|
|
#setopt "file" "opt" "=" "value" [";"]
|
|
_setopt() {
|
|
__conf="$1"
|
|
__opt="$2"
|
|
__sep="$3"
|
|
__val="$4"
|
|
__end="$5"
|
|
if [ -z "$__opt" ] ; then
|
|
echo usage: $0 '"file" "opt" "=" "value" [";"]'
|
|
return
|
|
fi
|
|
if [ ! -f "$__conf" ] ; then
|
|
touch "$__conf"
|
|
fi
|
|
if grep -H -n "^$__opt$__sep" "$__conf" > /dev/null ; then
|
|
_debug OK
|
|
if [[ "$__val" == *"&"* ]] ; then
|
|
__val="$(echo $__val | sed 's/&/\\&/g')"
|
|
fi
|
|
text="$(cat $__conf)"
|
|
printf "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf"
|
|
else
|
|
_debug APP
|
|
echo "$__opt$__sep$__val$__end" >> "$__conf"
|
|
fi
|
|
_debug "$(grep -H -n "^$__opt$__sep" $__conf)"
|
|
}
|
|
|
|
#_savedomainconf key value
|
|
#save to domain.conf
|
|
_savedomainconf() {
|
|
key="$1"
|
|
value="$2"
|
|
if [ "$DOMAIN_CONF" ] ; then
|
|
_setopt $DOMAIN_CONF "$key" "=" "$value"
|
|
else
|
|
_err "DOMAIN_CONF is empty, can not save $key=$value"
|
|
fi
|
|
}
|
|
|
|
#_saveaccountconf key value
|
|
_saveaccountconf() {
|
|
key="$1"
|
|
value="$2"
|
|
if [ "$ACCOUNT_CONF_PATH" ] ; then
|
|
_setopt $ACCOUNT_CONF_PATH "$key" "=" "$value"
|
|
else
|
|
_err "ACCOUNT_CONF_PATH is empty, can not save $key=$value"
|
|
fi
|
|
}
|
|
|
|
_startserver() {
|
|
content="$1"
|
|
_NC="nc -q 1"
|
|
if nc -h 2>&1 | grep "nmap.org/ncat" >/dev/null ; then
|
|
_NC="nc"
|
|
fi
|
|
# while true ; do
|
|
if [ "$DEBUG" ] ; then
|
|
echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort -vv
|
|
else
|
|
echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort > /dev/null
|
|
fi
|
|
# done
|
|
}
|
|
|
|
_stopserver() {
|
|
pid="$1"
|
|
|
|
}
|
|
|
|
_initpath() {
|
|
|
|
if [ -z "$LE_WORKING_DIR" ]; then
|
|
LE_WORKING_DIR=$HOME/.le
|
|
fi
|
|
|
|
if [ -z "$ACCOUNT_CONF_PATH" ] ; then
|
|
ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf"
|
|
fi
|
|
|
|
if [ -f "$ACCOUNT_CONF_PATH" ] ; then
|
|
source "$ACCOUNT_CONF_PATH"
|
|
fi
|
|
|
|
if [ -z "$API" ] ; then
|
|
if [ -z "$STAGE" ] ; then
|
|
API="$DEFAULT_CA"
|
|
else
|
|
API="$STAGE_CA"
|
|
_info "Using stage api:$API"
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$ACME_DIR" ] ; then
|
|
ACME_DIR="/home/.acme"
|
|
fi
|
|
|
|
if [ -z "$APACHE_CONF_BACKUP_DIR" ] ; then
|
|
APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR/"
|
|
fi
|
|
|
|
domain="$1"
|
|
mkdir -p "$LE_WORKING_DIR"
|
|
|
|
if [ -z "$ACCOUNT_KEY_PATH" ] ; then
|
|
ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key"
|
|
fi
|
|
|
|
if [ -z "$domain" ] ; then
|
|
return 0
|
|
fi
|
|
|
|
domainhome="$LE_WORKING_DIR/$domain"
|
|
mkdir -p "$domainhome"
|
|
|
|
if [ -z "$DOMAIN_CONF" ] ; then
|
|
DOMAIN_CONF="$domainhome/$Le_Domain.conf"
|
|
fi
|
|
|
|
if [ -z "$DOMAIN_SSL_CONF" ] ; then
|
|
DOMAIN_SSL_CONF="$domainhome/$Le_Domain.ssl.conf"
|
|
fi
|
|
|
|
if [ -z "$CSR_PATH" ] ; then
|
|
CSR_PATH="$domainhome/$domain.csr"
|
|
fi
|
|
if [ -z "$CERT_KEY_PATH" ] ; then
|
|
CERT_KEY_PATH="$domainhome/$domain.key"
|
|
fi
|
|
if [ -z "$CERT_PATH" ] ; then
|
|
CERT_PATH="$domainhome/$domain.cer"
|
|
fi
|
|
if [ -z "$CA_CERT_PATH" ] ; then
|
|
CA_CERT_PATH="$domainhome/ca.cer"
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
_apachePath() {
|
|
httpdroot="$(apachectl -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )"
|
|
httpdconfname="$(apachectl -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )"
|
|
httpdconf="$httpdroot/$httpdconfname"
|
|
if [ ! -f $httpdconf ] ; then
|
|
_err "Apache Config file not found" $httpdconf
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
_restoreApache() {
|
|
if [ -z "$usingApache" ] ; then
|
|
return 0
|
|
fi
|
|
_initpath
|
|
if ! _apachePath ; then
|
|
return 1
|
|
fi
|
|
|
|
if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ] ; then
|
|
_debug "No config file to restore."
|
|
return 0
|
|
fi
|
|
|
|
cp -p "$APACHE_CONF_BACKUP_DIR/$httpdconfname" "$httpdconf"
|
|
if ! apachectl -t ; then
|
|
_err "Sorry, restore apache config error, please contact me."
|
|
return 1;
|
|
fi
|
|
rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname"
|
|
return 0
|
|
}
|
|
|
|
_setApache() {
|
|
_initpath
|
|
if ! _apachePath ; then
|
|
return 1
|
|
fi
|
|
|
|
#backup the conf
|
|
_debug "Backup apache config file" $httpdconf
|
|
cp -p $httpdconf $APACHE_CONF_BACKUP_DIR/
|
|
_info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname"
|
|
_info "In case there is an error that can not be restored automatically, you may try restore it yourself."
|
|
_info "The backup file will be deleted on sucess, just forget it."
|
|
|
|
#add alias
|
|
echo "
|
|
Alias /.well-known/acme-challenge $ACME_DIR
|
|
|
|
<Directory $ACME_DIR >
|
|
Require all granted
|
|
</Directory>
|
|
" >> $httpdconf
|
|
|
|
if ! apachectl -t ; then
|
|
_err "Sorry, apache config error, please contact me."
|
|
_restoreApache
|
|
return 1;
|
|
fi
|
|
|
|
if [ ! -d "$ACME_DIR" ] ; then
|
|
mkdir -p "$ACME_DIR"
|
|
chmod 755 "$ACME_DIR"
|
|
fi
|
|
|
|
if ! apachectl graceful ; then
|
|
_err "Sorry, apachectl graceful error, please contact me."
|
|
_restoreApache
|
|
return 1;
|
|
fi
|
|
usingApache="1"
|
|
return 0
|
|
}
|
|
|
|
_clearup () {
|
|
_stopserver $serverproc
|
|
serverproc=""
|
|
_restoreApache
|
|
}
|
|
|
|
# webroot removelevel tokenfile
|
|
_clearupwebbroot() {
|
|
__webroot="$1"
|
|
if [ -z "$__webroot" ] ; then
|
|
_debug "no webroot specified, skip"
|
|
return 0
|
|
fi
|
|
|
|
if [ "$2" == '1' ] ; then
|
|
_debug "remove $__webroot/.well-known"
|
|
rm -rf "$__webroot/.well-known"
|
|
elif [ "$2" == '2' ] ; then
|
|
_debug "remove $__webroot/.well-known/acme-challenge"
|
|
rm -rf "$__webroot/.well-known/acme-challenge"
|
|
elif [ "$2" == '3' ] ; then
|
|
_debug "remove $__webroot/.well-known/acme-challenge/$3"
|
|
rm -rf "$__webroot/.well-known/acme-challenge/$3"
|
|
else
|
|
_info "Skip for removelevel:$2"
|
|
fi
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
issue() {
|
|
if [ -z "$2" ] ; then
|
|
_err "Usage: le issue webroot|no|apache|dns a.com [www.a.com,b.com,c.com]|no [key-length]|no"
|
|
return 1
|
|
fi
|
|
Le_Webroot="$1"
|
|
Le_Domain="$2"
|
|
Le_Alt="$3"
|
|
Le_Keylength="$4"
|
|
Le_RealCertPath="$5"
|
|
Le_RealKeyPath="$6"
|
|
Le_RealCACertPath="$7"
|
|
Le_ReloadCmd="$8"
|
|
|
|
|
|
_initpath $Le_Domain
|
|
|
|
if [ -f "$DOMAIN_CONF" ] ; then
|
|
Le_NextRenewTime=$(grep "^Le_NextRenewTime=" "$DOMAIN_CONF" | cut -d '=' -f 2)
|
|
if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then
|
|
_info "Skip, Next renewal time is: $(grep "^Le_NextRenewTimeStr" "$DOMAIN_CONF" | cut -d '=' -f 2)"
|
|
return 2
|
|
fi
|
|
fi
|
|
|
|
if [ "$Le_Alt" == "no" ] ; then
|
|
Le_Alt=""
|
|
fi
|
|
if [ "$Le_Keylength" == "no" ] ; then
|
|
Le_Keylength=""
|
|
fi
|
|
if [ "$Le_RealCertPath" == "no" ] ; then
|
|
Le_RealCertPath=""
|
|
fi
|
|
if [ "$Le_RealKeyPath" == "no" ] ; then
|
|
Le_RealKeyPath=""
|
|
fi
|
|
if [ "$Le_RealCACertPath" == "no" ] ; then
|
|
Le_RealCACertPath=""
|
|
fi
|
|
if [ "$Le_ReloadCmd" == "no" ] ; then
|
|
Le_ReloadCmd=""
|
|
fi
|
|
|
|
_setopt "$DOMAIN_CONF" "Le_Domain" "=" "$Le_Domain"
|
|
_setopt "$DOMAIN_CONF" "Le_Alt" "=" "$Le_Alt"
|
|
_setopt "$DOMAIN_CONF" "Le_Webroot" "=" "$Le_Webroot"
|
|
_setopt "$DOMAIN_CONF" "Le_Keylength" "=" "$Le_Keylength"
|
|
_setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\""
|
|
_setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\""
|
|
_setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\""
|
|
_setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\""
|
|
|
|
if [ "$Le_Webroot" == "no" ] ; then
|
|
_info "Standalone mode."
|
|
if ! command -v "nc" > /dev/null ; then
|
|
_err "Please install netcat(nc) tools first."
|
|
return 1
|
|
fi
|
|
|
|
if [ -z "$Le_HTTPPort" ] ; then
|
|
Le_HTTPPort=80
|
|
fi
|
|
_setopt "$DOMAIN_CONF" "Le_HTTPPort" "=" "$Le_HTTPPort"
|
|
|
|
netprc="$(ss -ntpl | grep :$Le_HTTPPort" ")"
|
|
if [ "$netprc" ] ; then
|
|
_err "$netprc"
|
|
_err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)"
|
|
_err "Please stop it first"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
if [ "$Le_Webroot" == "apache" ] ; then
|
|
if ! _setApache ; then
|
|
_err "set up apache error. Report error to me."
|
|
return 1
|
|
fi
|
|
wellknown_path="$ACME_DIR"
|
|
else
|
|
usingApache=""
|
|
fi
|
|
|
|
createAccountKey $Le_Domain $Le_Keylength
|
|
|
|
if ! createDomainKey $Le_Domain $Le_Keylength ; then
|
|
_err "Create domain key error."
|
|
return 1
|
|
fi
|
|
|
|
if ! createCSR $Le_Domain $Le_Alt ; then
|
|
_err "Create CSR error."
|
|
return 1
|
|
fi
|
|
|
|
pub_exp=$(openssl rsa -in $ACCOUNT_KEY_PATH -noout -text | grep "^publicExponent:"| cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
|
|
if [ "${#pub_exp}" == "5" ] ; then
|
|
pub_exp=0$pub_exp
|
|
fi
|
|
_debug pub_exp "$pub_exp"
|
|
|
|
e=$(echo $pub_exp | _h2b | _base64)
|
|
_debug e "$e"
|
|
|
|
modulus=$(openssl rsa -in $ACCOUNT_KEY_PATH -modulus -noout | cut -d '=' -f 2 )
|
|
n=$(echo $modulus| _h2b | _base64 | _b64 )
|
|
|
|
jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}'
|
|
|
|
HEADER='{"alg": "RS256", "jwk": '$jwk'}'
|
|
HEADERPLACE='{"nonce": "NONCE", "alg": "RS256", "jwk": '$jwk'}'
|
|
_debug HEADER "$HEADER"
|
|
|
|
accountkey_json=$(echo -n "$jwk" | tr -d ' ' )
|
|
thumbprint=$(echo -n "$accountkey_json" | openssl dgst -sha256 -binary | _base64 | _b64)
|
|
|
|
|
|
_info "Registering account"
|
|
regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}'
|
|
if [ "$ACCOUNT_EMAIL" ] ; then
|
|
regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}'
|
|
fi
|
|
_send_signed_request "$API/acme/new-reg" "$regjson"
|
|
|
|
if [ "$code" == "" ] || [ "$code" == '201' ] ; then
|
|
_info "Registered"
|
|
echo $response > $LE_WORKING_DIR/account.json
|
|
elif [ "$code" == '409' ] ; then
|
|
_info "Already registered"
|
|
else
|
|
_err "Register account Error."
|
|
_clearup
|
|
return 1
|
|
fi
|
|
|
|
vtype="$VTYPE_HTTP"
|
|
if [[ "$Le_Webroot" == "dns"* ]] ; then
|
|
vtype="$VTYPE_DNS"
|
|
fi
|
|
|
|
vlist="$Le_Vlist"
|
|
# verify each domain
|
|
_info "Verify each domain"
|
|
sep='#'
|
|
if [ -z "$vlist" ] ; then
|
|
alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' )
|
|
for d in $alldomains
|
|
do
|
|
_info "Geting token for domain" $d
|
|
_send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}"
|
|
if [ ! -z "$code" ] && [ ! "$code" == '201' ] ; then
|
|
_err "new-authz error: $response"
|
|
_clearup
|
|
return 1
|
|
fi
|
|
|
|
entry="$(printf $response | egrep -o '{[^{]*"type":"'$vtype'"[^}]*')"
|
|
_debug entry "$entry"
|
|
|
|
token="$(printf "$entry" | egrep -o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
|
|
_debug token $token
|
|
|
|
uri="$(printf "$entry" | egrep -o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )"
|
|
_debug uri $uri
|
|
|
|
keyauthorization="$token.$thumbprint"
|
|
_debug keyauthorization "$keyauthorization"
|
|
|
|
dvlist="$d$sep$keyauthorization$sep$uri"
|
|
_debug dvlist "$dvlist"
|
|
|
|
vlist="$vlist$dvlist,"
|
|
|
|
done
|
|
|
|
#add entry
|
|
dnsadded=""
|
|
ventries=$(echo "$vlist" | tr ',' ' ' )
|
|
for ventry in $ventries
|
|
do
|
|
d=$(echo $ventry | cut -d $sep -f 1)
|
|
keyauthorization=$(echo $ventry | cut -d $sep -f 2)
|
|
|
|
if [ "$vtype" == "$VTYPE_DNS" ] ; then
|
|
dnsadded='0'
|
|
txtdomain="_acme-challenge.$d"
|
|
_debug txtdomain "$txtdomain"
|
|
txt="$(echo -e -n $keyauthorization | openssl dgst -sha256 -binary | _base64 | _b64)"
|
|
_debug txt "$txt"
|
|
#dns
|
|
#1. check use api
|
|
d_api=""
|
|
if [ -f "$LE_WORKING_DIR/$d/$Le_Webroot" ] ; then
|
|
d_api="$LE_WORKING_DIR/$d/$Le_Webroot"
|
|
elif [ -f "$LE_WORKING_DIR/$d/$Le_Webroot.sh" ] ; then
|
|
d_api="$LE_WORKING_DIR/$d/$Le_Webroot.sh"
|
|
elif [ -f "$LE_WORKING_DIR/$Le_Webroot" ] ; then
|
|
d_api="$LE_WORKING_DIR/$Le_Webroot"
|
|
elif [ -f "$LE_WORKING_DIR/$Le_Webroot.sh" ] ; then
|
|
d_api="$LE_WORKING_DIR/$Le_Webroot.sh"
|
|
elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot" ] ; then
|
|
d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot"
|
|
elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh" ] ; then
|
|
d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh"
|
|
fi
|
|
_debug d_api "$d_api"
|
|
|
|
if [ "$d_api" ]; then
|
|
_info "Found domain api file: $d_api"
|
|
else
|
|
_err "Add the following TXT record:"
|
|
_err "Domain: $txtdomain"
|
|
_err "TXT value: $txt"
|
|
_err "Please be aware that you prepend _acme-challenge. before your domain"
|
|
_err "so the resulting subdomain will be: $txtdomain"
|
|
continue
|
|
fi
|
|
|
|
if ! source $d_api ; then
|
|
_err "Load file $d_api error. Please check your api file and try again."
|
|
return 1
|
|
fi
|
|
|
|
addcommand="$Le_Webroot-add"
|
|
if ! command -v $addcommand ; then
|
|
_err "It seems that your api file is not correct, it must have a function named: $Le_Webroot"
|
|
return 1
|
|
fi
|
|
|
|
if ! $addcommand $txtdomain $txt ; then
|
|
_err "Error add txt for domain:$txtdomain"
|
|
return 1
|
|
fi
|
|
dnsadded='1'
|
|
fi
|
|
done
|
|
|
|
if [ "$dnsadded" == '0' ] ; then
|
|
_setopt "$DOMAIN_CONF" "Le_Vlist" "=" "\"$vlist\""
|
|
_debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
|
|
_err "Please add the TXT records to the domains, and retry again."
|
|
return 1
|
|
fi
|
|
|
|
fi
|
|
|
|
if [ "$dnsadded" == '1' ] ; then
|
|
_info "Sleep 60 seconds for the txt records to take effect"
|
|
sleep 60
|
|
fi
|
|
|
|
_debug "ok, let's start to verify"
|
|
ventries=$(echo "$vlist" | tr ',' ' ' )
|
|
for ventry in $ventries
|
|
do
|
|
d=$(echo $ventry | cut -d $sep -f 1)
|
|
keyauthorization=$(echo $ventry | cut -d $sep -f 2)
|
|
uri=$(echo $ventry | cut -d $sep -f 3)
|
|
_info "Verifying:$d"
|
|
_debug "d" "$d"
|
|
_debug "keyauthorization" "$keyauthorization"
|
|
_debug "uri" "$uri"
|
|
removelevel=""
|
|
token=""
|
|
if [ "$vtype" == "$VTYPE_HTTP" ] ; then
|
|
if [ "$Le_Webroot" == "no" ] ; then
|
|
_info "Standalone mode server"
|
|
_startserver "$keyauthorization" &
|
|
serverproc="$!"
|
|
sleep 2
|
|
_debug serverproc $serverproc
|
|
else
|
|
if [ -z "$wellknown_path" ] ; then
|
|
wellknown_path="$Le_Webroot/.well-known/acme-challenge"
|
|
fi
|
|
_debug wellknown_path "$wellknown_path"
|
|
|
|
if [ ! -d "$Le_Webroot/.well-known" ] ; then
|
|
removelevel='1'
|
|
elif [ ! -d "$Le_Webroot/.well-known/acme-challenge" ] ; then
|
|
removelevel='2'
|
|
else
|
|
removelevel='3'
|
|
fi
|
|
|
|
token="$(echo -e -n "$keyauthorization" | cut -d '.' -f 1)"
|
|
_debug "writing token:$token to $wellknown_path/$token"
|
|
|
|
mkdir -p "$wellknown_path"
|
|
echo -n "$keyauthorization" > "$wellknown_path/$token"
|
|
|
|
webroot_owner=$(stat -c '%U:%G' $Le_Webroot)
|
|
_debug "Changing owner/group of .well-known to $webroot_owner"
|
|
chown -R $webroot_owner "$Le_Webroot/.well-known"
|
|
|
|
fi
|
|
fi
|
|
|
|
_send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"
|
|
|
|
if [ ! -z "$code" ] && [ ! "$code" == '202' ] ; then
|
|
_err "$d:Challenge error: $resource"
|
|
_clearupwebbroot "$Le_Webroot" "$removelevel" "$token"
|
|
_clearup
|
|
return 1
|
|
fi
|
|
|
|
while [ "1" ] ; do
|
|
_debug "sleep 5 secs to verify"
|
|
sleep 5
|
|
_debug "checking"
|
|
|
|
if ! _get $uri ; then
|
|
_err "$d:Verify error:$resource"
|
|
_clearupwebbroot "$Le_Webroot" "$removelevel" "$token"
|
|
_clearup
|
|
return 1
|
|
fi
|
|
|
|
status=$(echo $response | egrep -o '"status":"[^"]+"' | cut -d : -f 2 | tr -d '"')
|
|
if [ "$status" == "valid" ] ; then
|
|
_info "Success"
|
|
_stopserver $serverproc
|
|
serverproc=""
|
|
_clearupwebbroot "$Le_Webroot" "$removelevel" "$token"
|
|
break;
|
|
fi
|
|
|
|
if [ "$status" == "invalid" ] ; then
|
|
error=$(echo $response | egrep -o '"error":{[^}]*}' | grep -o '"detail":"[^"]*"' | cut -d '"' -f 4)
|
|
_err "$d:Verify error:$error"
|
|
_clearupwebbroot "$Le_Webroot" "$removelevel" "$token"
|
|
_clearup
|
|
return 1;
|
|
fi
|
|
|
|
if [ "$status" == "pending" ] ; then
|
|
_info "Pending"
|
|
else
|
|
_err "$d:Verify error:$response"
|
|
_clearupwebbroot "$Le_Webroot" "$removelevel" "$token"
|
|
_clearup
|
|
return 1
|
|
fi
|
|
|
|
done
|
|
|
|
done
|
|
|
|
_clearup
|
|
_info "Verify finished, start to sign."
|
|
der="$(openssl req -in $CSR_PATH -outform DER | _base64 | _b64)"
|
|
_send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"
|
|
|
|
|
|
Le_LinkCert="$(grep -i -o '^Location.*$' $CURL_HEADER | tr -d "\r\n" | cut -d " " -f 2)"
|
|
_setopt "$DOMAIN_CONF" "Le_LinkCert" "=" "$Le_LinkCert"
|
|
|
|
if [ "$Le_LinkCert" ] ; then
|
|
echo -----BEGIN CERTIFICATE----- > "$CERT_PATH"
|
|
curl --silent "$Le_LinkCert" | openssl base64 -e >> "$CERT_PATH"
|
|
echo -----END CERTIFICATE----- >> "$CERT_PATH"
|
|
_info "Cert success."
|
|
cat "$CERT_PATH"
|
|
|
|
_info "Your cert is in $CERT_PATH"
|
|
fi
|
|
|
|
|
|
if [ -z "$Le_LinkCert" ] ; then
|
|
response="$(echo $response | openssl base64 -d -A)"
|
|
_err "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')"
|
|
return 1
|
|
fi
|
|
|
|
_setopt "$DOMAIN_CONF" 'Le_Vlist' '=' "\"\""
|
|
|
|
Le_LinkIssuer=$(grep -i '^Link' $CURL_HEADER | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' )
|
|
_setopt "$DOMAIN_CONF" "Le_LinkIssuer" "=" "$Le_LinkIssuer"
|
|
|
|
if [ "$Le_LinkIssuer" ] ; then
|
|
echo -----BEGIN CERTIFICATE----- > "$CA_CERT_PATH"
|
|
curl --silent "$Le_LinkIssuer" | openssl base64 -e >> "$CA_CERT_PATH"
|
|
echo -----END CERTIFICATE----- >> "$CA_CERT_PATH"
|
|
_info "The intermediate CA cert is in $CA_CERT_PATH"
|
|
fi
|
|
|
|
Le_CertCreateTime=$(date -u "+%s")
|
|
_setopt "$DOMAIN_CONF" "Le_CertCreateTime" "=" "$Le_CertCreateTime"
|
|
|
|
Le_CertCreateTimeStr=$(date -u )
|
|
_setopt "$DOMAIN_CONF" "Le_CertCreateTimeStr" "=" "\"$Le_CertCreateTimeStr\""
|
|
|
|
if [ ! "$Le_RenewalDays" ] ; then
|
|
Le_RenewalDays=80
|
|
fi
|
|
|
|
_setopt "$DOMAIN_CONF" "Le_RenewalDays" "=" "$Le_RenewalDays"
|
|
|
|
let "Le_NextRenewTime=Le_CertCreateTime+Le_RenewalDays*24*60*60"
|
|
_setopt "$DOMAIN_CONF" "Le_NextRenewTime" "=" "$Le_NextRenewTime"
|
|
|
|
Le_NextRenewTimeStr=$( _time2str $Le_NextRenewTime )
|
|
_setopt "$DOMAIN_CONF" "Le_NextRenewTimeStr" "=" "\"$Le_NextRenewTimeStr\""
|
|
|
|
|
|
installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd"
|
|
|
|
}
|
|
|
|
renew() {
|
|
Le_Domain="$1"
|
|
if [ -z "$Le_Domain" ] ; then
|
|
_err "Usage: $0 domain.com"
|
|
return 1
|
|
fi
|
|
|
|
_initpath $Le_Domain
|
|
|
|
if [ ! -f "$DOMAIN_CONF" ] ; then
|
|
_info "$Le_Domain is not a issued domain, skip."
|
|
return 0;
|
|
fi
|
|
|
|
source "$DOMAIN_CONF"
|
|
if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then
|
|
_info "Skip, Next renewal time is: $Le_NextRenewTimeStr"
|
|
return 2
|
|
fi
|
|
|
|
IS_RENEW="1"
|
|
issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd"
|
|
local res=$?
|
|
IS_RENEW=""
|
|
|
|
return $res
|
|
}
|
|
|
|
renewAll() {
|
|
_initpath
|
|
_info "renewAll"
|
|
|
|
for d in $(ls -F $LE_WORKING_DIR | grep [^.].*[.].*/$ ) ; do
|
|
d=$(echo $d | cut -d '/' -f 1)
|
|
_info "renew $d"
|
|
|
|
Le_LinkCert=""
|
|
Le_Domain=""
|
|
Le_Alt=""
|
|
Le_Webroot=""
|
|
Le_Keylength=""
|
|
Le_LinkIssuer=""
|
|
|
|
Le_CertCreateTime=""
|
|
Le_CertCreateTimeStr=""
|
|
Le_RenewalDays=""
|
|
Le_NextRenewTime=""
|
|
Le_NextRenewTimeStr=""
|
|
|
|
Le_RealCertPath=""
|
|
Le_RealKeyPath=""
|
|
|
|
Le_RealCACertPath=""
|
|
|
|
Le_ReloadCmd=""
|
|
|
|
DOMAIN_CONF=""
|
|
DOMAIN_SSL_CONF=""
|
|
CSR_PATH=""
|
|
CERT_KEY_PATH=""
|
|
CERT_PATH=""
|
|
CA_CERT_PATH=""
|
|
ACCOUNT_KEY_PATH=""
|
|
|
|
wellknown_path=""
|
|
|
|
renew "$d"
|
|
done
|
|
|
|
}
|
|
|
|
installcert() {
|
|
Le_Domain="$1"
|
|
if [ -z "$Le_Domain" ] ; then
|
|
_err "Usage: $0 domain.com [cert-file-path]|no [key-file-path]|no [ca-cert-file-path]|no [reloadCmd]|no"
|
|
return 1
|
|
fi
|
|
|
|
Le_RealCertPath="$2"
|
|
Le_RealKeyPath="$3"
|
|
Le_RealCACertPath="$4"
|
|
Le_ReloadCmd="$5"
|
|
|
|
_initpath $Le_Domain
|
|
|
|
_setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\""
|
|
_setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\""
|
|
_setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\""
|
|
_setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\""
|
|
|
|
if [ "$Le_RealCertPath" ] ; then
|
|
if [ -f "$Le_RealCertPath" ] ; then
|
|
cp -p "$Le_RealCertPath" "$Le_RealCertPath".bak
|
|
fi
|
|
cat "$CERT_PATH" > "$Le_RealCertPath"
|
|
fi
|
|
|
|
if [ "$Le_RealCACertPath" ] ; then
|
|
if [ -f "$Le_RealCACertPath" ] ; then
|
|
cp -p "$Le_RealCACertPath" "$Le_RealCACertPath".bak
|
|
fi
|
|
if [ "$Le_RealCACertPath" == "$Le_RealCertPath" ] ; then
|
|
echo "" >> "$Le_RealCACertPath"
|
|
cat "$CA_CERT_PATH" >> "$Le_RealCACertPath"
|
|
else
|
|
cat "$CA_CERT_PATH" > "$Le_RealCACertPath"
|
|
fi
|
|
fi
|
|
|
|
|
|
if [ "$Le_RealKeyPath" ] ; then
|
|
if [ -f "$Le_RealKeyPath" ] ; then
|
|
cp -p "$Le_RealKeyPath" "$Le_RealKeyPath".bak
|
|
fi
|
|
cat "$CERT_KEY_PATH" > "$Le_RealKeyPath"
|
|
fi
|
|
|
|
if [ "$Le_ReloadCmd" ] ; then
|
|
_info "Run Le_ReloadCmd: $Le_ReloadCmd"
|
|
$Le_ReloadCmd
|
|
fi
|
|
|
|
}
|
|
|
|
installcronjob() {
|
|
_initpath
|
|
_info "Installing cron job"
|
|
if ! crontab -l | grep 'le.sh cron' ; then
|
|
if [ -f "$LE_WORKING_DIR/le.sh" ] ; then
|
|
lesh="\"$LE_WORKING_DIR\"/le.sh"
|
|
else
|
|
_err "Can not install cronjob, le.sh not found."
|
|
return 1
|
|
fi
|
|
crontab -l | { cat; echo "0 0 * * * LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null"; } | crontab -
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
uninstallcronjob() {
|
|
_info "Removing cron job"
|
|
cr="$(crontab -l | grep 'le.sh cron')"
|
|
if [ "$cr" ] ; then
|
|
crontab -l | sed "/le.sh cron/d" | crontab -
|
|
LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 6 | cut -d '=' -f 2 | tr -d '"')"
|
|
_info LE_WORKING_DIR "$LE_WORKING_DIR"
|
|
fi
|
|
_initpath
|
|
|
|
}
|
|
|
|
|
|
# Detect profile file if not specified as environment variable
|
|
_detect_profile() {
|
|
if [ -n "$PROFILE" -a -f "$PROFILE" ]; then
|
|
echo "$PROFILE"
|
|
return
|
|
fi
|
|
|
|
local DETECTED_PROFILE
|
|
DETECTED_PROFILE=''
|
|
local SHELLTYPE
|
|
SHELLTYPE="$(basename "/$SHELL")"
|
|
|
|
if [ "$SHELLTYPE" = "bash" ]; then
|
|
if [ -f "$HOME/.bashrc" ]; then
|
|
DETECTED_PROFILE="$HOME/.bashrc"
|
|
elif [ -f "$HOME/.bash_profile" ]; then
|
|
DETECTED_PROFILE="$HOME/.bash_profile"
|
|
fi
|
|
elif [ "$SHELLTYPE" = "zsh" ]; then
|
|
DETECTED_PROFILE="$HOME/.zshrc"
|
|
fi
|
|
|
|
if [ -z "$DETECTED_PROFILE" ]; then
|
|
if [ -f "$HOME/.profile" ]; then
|
|
DETECTED_PROFILE="$HOME/.profile"
|
|
elif [ -f "$HOME/.bashrc" ]; then
|
|
DETECTED_PROFILE="$HOME/.bashrc"
|
|
elif [ -f "$HOME/.bash_profile" ]; then
|
|
DETECTED_PROFILE="$HOME/.bash_profile"
|
|
elif [ -f "$HOME/.zshrc" ]; then
|
|
DETECTED_PROFILE="$HOME/.zshrc"
|
|
fi
|
|
fi
|
|
|
|
if [ ! -z "$DETECTED_PROFILE" ]; then
|
|
echo "$DETECTED_PROFILE"
|
|
fi
|
|
}
|
|
|
|
_initconf() {
|
|
_initpath
|
|
if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then
|
|
echo "#Account configurations:
|
|
#Here are the supported macros, uncomment them to make them take effect.
|
|
#ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account.
|
|
|
|
#STAGE=1 # Use the staging api
|
|
#FORCE=1 # Force to issue cert
|
|
#DEBUG=1 # Debug mode
|
|
|
|
#dns api
|
|
#######################
|
|
#Cloudflare:
|
|
#api key
|
|
#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
|
#account email
|
|
#CF_Email="xxxx@sss.com"
|
|
|
|
#######################
|
|
#Dnspod.cn:
|
|
#api key id
|
|
#DP_Id="1234"
|
|
#api key
|
|
#DP_Key="sADDsdasdgdsf"
|
|
|
|
#######################
|
|
#Cloudxns.com:
|
|
#CX_Key="1234"
|
|
#
|
|
#CX_Secret="sADDsdasdgdsf"
|
|
|
|
" > $ACCOUNT_CONF_PATH
|
|
fi
|
|
}
|
|
|
|
install() {
|
|
_initpath
|
|
|
|
#check if there is sudo installed, AND if the current user is a sudoer.
|
|
if command -v sudo > /dev/null ; then
|
|
if [ "$(sudo -n uptime 2>&1|grep "load"|wc -l)" != "0" ] ; then
|
|
SUDO=sudo
|
|
fi
|
|
fi
|
|
|
|
if command -v yum > /dev/null ; then
|
|
YUM="1"
|
|
INSTALL="$SUDO yum install -y "
|
|
elif command -v apt-get > /dev/null ; then
|
|
INSTALL="$SUDO apt-get install -y "
|
|
fi
|
|
|
|
if ! command -v "curl" > /dev/null ; then
|
|
_err "Please install curl first."
|
|
_err "$INSTALL curl"
|
|
return 1
|
|
fi
|
|
|
|
if ! command -v "crontab" > /dev/null ; then
|
|
_err "Please install crontab first."
|
|
if [ "$YUM" ] ; then
|
|
_err "$INSTALL crontabs"
|
|
else
|
|
_err "$INSTALL crontab"
|
|
fi
|
|
return 1
|
|
fi
|
|
|
|
if ! command -v "openssl" > /dev/null ; then
|
|
_err "Please install openssl first."
|
|
_err "$INSTALL openssl"
|
|
return 1
|
|
fi
|
|
|
|
_info "Installing to $LE_WORKING_DIR"
|
|
|
|
_info "Installed to $LE_WORKING_DIR/le.sh"
|
|
cp le.sh $LE_WORKING_DIR/
|
|
chmod +x $LE_WORKING_DIR/le.sh
|
|
|
|
_profile="$(_detect_profile)"
|
|
if [ "$_profile" ] ; then
|
|
_debug "Found profile: $_profile"
|
|
|
|
echo "LE_WORKING_DIR=$LE_WORKING_DIR
|
|
alias le=\"$LE_WORKING_DIR/le.sh\"
|
|
alias le.sh=\"$LE_WORKING_DIR/le.sh\"
|
|
" > "$LE_WORKING_DIR/le.env"
|
|
|
|
_setopt "$_profile" "source \"$LE_WORKING_DIR/le.env\""
|
|
_info "OK, Close and reopen your terminal to start using le"
|
|
else
|
|
_info "No profile is found, you will need to go into $LE_WORKING_DIR to use le.sh"
|
|
fi
|
|
|
|
mkdir -p $LE_WORKING_DIR/dnsapi
|
|
cp dnsapi/* $LE_WORKING_DIR/dnsapi/
|
|
|
|
#to keep compatible mv the .acc file to .key file
|
|
if [ -f "$LE_WORKING_DIR/account.acc" ] ; then
|
|
mv "$LE_WORKING_DIR/account.acc" "$LE_WORKING_DIR/account.key"
|
|
fi
|
|
|
|
installcronjob
|
|
|
|
if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then
|
|
_initconf
|
|
fi
|
|
_info OK
|
|
}
|
|
|
|
uninstall() {
|
|
uninstallcronjob
|
|
_initpath
|
|
|
|
_profile="$(_detect_profile)"
|
|
if [ "$_profile" ] ; then
|
|
sed -i /le.env/d "$_profile"
|
|
fi
|
|
|
|
rm -f $LE_WORKING_DIR/le.sh
|
|
_info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself."
|
|
|
|
}
|
|
|
|
cron() {
|
|
renewAll
|
|
}
|
|
|
|
version() {
|
|
_info "$PROJECT"
|
|
_info "v$VER"
|
|
}
|
|
|
|
showhelp() {
|
|
version
|
|
echo "Usage: le.sh [command] ...[args]....
|
|
Avalible commands:
|
|
|
|
install:
|
|
Install le.sh to your system.
|
|
issue:
|
|
Issue a cert.
|
|
installcert:
|
|
Install the issued cert to apache/nginx or any other server.
|
|
renew:
|
|
Renew a cert.
|
|
renewAll:
|
|
Renew all the certs.
|
|
uninstall:
|
|
Uninstall le.sh, and uninstall the cron job.
|
|
version:
|
|
Show version info.
|
|
installcronjob:
|
|
Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
|
|
uninstallcronjob:
|
|
Uninstall the cron job. The 'uninstall' command can do this automatically.
|
|
createAccountKey:
|
|
Create an account private key, professional use.
|
|
createDomainKey:
|
|
Create an domain private key, professional use.
|
|
createCSR:
|
|
Create CSR , professional use.
|
|
"
|
|
}
|
|
|
|
|
|
if [ -z "$1" ] ; then
|
|
showhelp
|
|
else
|
|
"$@"
|
|
fi
|