Skip to content

Commit

Permalink
Merge pull request #50 from Koumbit/43-options_to_limit_requested_cer…
Browse files Browse the repository at this point in the history
…tificates

Fixes #43 and #48: Option to limit requested certificates
  • Loading branch information
camlafit committed Jul 23, 2019
2 parents 04fa361 + 4e1973a commit fc93ca9
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 73 deletions.
2 changes: 1 addition & 1 deletion src/etc/cron.d/alternc-certbot
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Twice a day, every 12 hours :
# - renew the certificate of the panel (alternc-cerbot)
# - generate or renew the certificates of every domain available (generate_certbot.php via alternc-certbot)
0 */12 * * * root /usr/lib/alternc/install.d/alternc-certbot apache2 --quiet
0 */12 * * * root /usr/lib/alternc/install.d/alternc-certbot apache2 --quiet --all
189 changes: 118 additions & 71 deletions src/usr/lib/alternc/generate_certbot.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,59 @@
* using Letsencrypt and ACME 1.0 protocol, with HTTP validation
* Called as a cron or as an interactive script during alternc.install
*
* usage: -v | --verbose display progress information (default = quiet)
* usage: [-v | --verbose] [-c TYPE | --certificates TYPE]
* --verbose display progress information (default = quiet)
* --certificates TYPE which type of certificates to request: all, system, non-system
*
* certificates defaults to "all", or the value of the environment variable
* ALTERNC_REQUEST_CERTIFICATES (eg. in /etc/alternc/local.sh).
*/

// Renew a domain if we don't have a cert or if it expires $VALID_DAYS from now
$VALID_DAYS = 30;
$VALID_DAYS = 30;
// Use the difference in seconds to avoid re-calculating the value for each sub-domain
$VALID_DIFF = 86400 * 30;

// Which type of certificates should be requested: all, system, non-system.
$REQUEST_CERTS="all";
$ALLOWED_CERT_TYPES = array(
'all',
'system',
'non-system',
);

// Use the environment variable as the default if it set.
if (getenv('ALTERNC_REQUEST_CERTIFICATES') !== FALSE) {
$REQUEST_CERTS = getenv('ALTERNC_REQUEST_CERTIFICATES');
}

$short_options = 'vc:';
$long_options = array(
'verbose',
'certificates:'
);
$options = getopt($short_options, $long_options);

$verbose = (in_array('v', array_keys($options)) || in_array('verbose', array_keys($options))) ? True : False;

// Use --certificates if it is set in priorirty, otherwise choose '-c', or if that
// isn't set, use the default value.
$REQUEST_CERTS= in_array('certificates', array_keys($options)) ? $options['certificates'] : (
in_array('c', array_keys($options)) ? $options['c'] : $REQUEST_CERTS);

// Handle the verbose flag
$verbose = ( $argc > 1 && in_array( $argv[1], array( "-v", "--verbose") ) ) ? True : False;
function vprint( $message, $params ){
global $verbose;
if( $verbose ) {
echo vsprintf( "$message", $params );
}
}

if (!in_array($REQUEST_CERTS, $ALLOWED_CERT_TYPES)) {
printf(_("Error: Requested certificate type '%s' not one of the allowed types: %s"),
$REQUEST_CERTS, print_r($ALLOWED_CERT_TYPES, TRUE));
exit(1);
}

// Bootstrap without session check
chdir("/usr/share/alternc/panel/");
require("/usr/share/alternc/panel/class/config_nochk.php");
Expand All @@ -38,84 +75,94 @@ function vprint( $message, $params ){
$spacer=" ";

// Request system domains before user certificates.
foreach($ssl->get_fqdn_specials() as $specialfqdn) {
vprint( _("\r$spacer\rRequesting domain %s"), array( $specialfqdn ));
if( ! $certbot->isLocalAlterncDomain( $specialfqdn ) ){
continue;
}
vprint( _(" hosted locally, running certbot..."), array( ));
if ($REQUEST_CERTS == 'all' || $REQUEST_CERTS == 'system') {
foreach($ssl->get_fqdn_specials() as $specialfqdn) {
vprint( _("\r$spacer\rRequesting domain %s"), array( $specialfqdn ));
if( ! $certbot->isLocalAlterncDomain( $specialfqdn ) ){
continue;
}
vprint( _(" hosted locally, running certbot..."), array( ));

$certbot->import($specialfqdn);
$certbot->import($specialfqdn);
}
vprintf(_("\rFinished renewal for system certificates\n"), array());
}
else {
vprint(_("Skipping system certificates, requested certificates type: %s\n"), array($REQUEST_CERTS));
}

// Get all alternc accounts
$accounts = $admin->get_list(1, 0, false, 'domaine');

// Retrieve every information of every subdomains from user accounts
// (only those for which only_dns is false (they have vhosts)
$domainsList = array();
foreach ($accounts as $cuid => $infos) {
$mem->su($cuid);
// Get all domain set to each user
$domains = $dom->enum_domains();
foreach ($domains as $domain) {
$dom->lock();
$domain_data = $dom->get_domain_all($domain);
// Get all hosts (subdomain)
if (!isset($domain_data['sub'])) {
continue;
}
foreach ($domain_data['sub'] as $sub_domain) {
if (in_array($sub_domain['type'], $is_vhost) &&
$is_vhost[strtolower($sub_domain["type"])]) {
$domainsList[] = array('sub_domain' => $sub_domain, 'cuid' => $cuid);
if ($REQUEST_CERTS == 'all' || $REQUEST_CERTS == 'non-system') {
// Get all alternc accounts
$accounts = $admin->get_list(1, 0, false, 'domaine');

// Retrieve every information of every subdomains from user accounts
// (only those for which only_dns is false (they have vhosts)
$domainsList = array();
foreach ($accounts as $cuid => $infos) {
$mem->su($cuid);
// Get all domain set to each user
$domains = $dom->enum_domains();
foreach ($domains as $domain) {
$dom->lock();
$domain_data = $dom->get_domain_all($domain);
// Get all hosts (subdomain)
if (!isset($domain_data['sub'])) {
continue;
}
foreach ($domain_data['sub'] as $sub_domain) {
if (in_array($sub_domain['type'], $is_vhost) &&
$is_vhost[strtolower($sub_domain["type"])]) {
$domainsList[] = array('sub_domain' => $sub_domain, 'cuid' => $cuid);
}
}
$dom->unlock();
}
$dom->unlock();
$mem->unsu();
}
$mem->unsu();
}

// Need to request anything:
if( count( $domainsList ) ){

vprint( _("Requiring Certbot renewal for %s domains\n"), count( $domainsList ));

foreach ($domainsList as $key => $sub_domain) {
$mem->su($sub_domain["cuid"]);
// Check if we already have a valid cert for this domain (valid for more than $VALID_DAYS days
// Either the subdomain (first, quicker), or any Certificate found for this FQDN
if (isset($sub_domain['domain']["certificate_id"])) {

// trick below: false=>not found, 0 => Snakeoil == skip both
if ( $current = $ssl->get_certificate($sub_domain["sub_domain"]["certificate_id"],true) ) {

// found, is it valid ? (fqdn match) (skips panel one)
if ($ssl->fqdnMatch($current["fqdn"],$sub_domain["sub_domain"]["fqdn"])) {
// found and valid, (works for wildcards too ;) )
// now what about the date?
if ($current["validstartts"]>time()
&& $current["validendts"]>(time()+(86400*$VALID_DAYS))
) {
// valid at least for $VALID_DAYS from now, let's skip this one for now
continue;
// Need to request anything:
if( count( $domainsList ) ){

vprint( _("Requiring Certbot renewal for %s domains\n"), count( $domainsList ));
foreach ($domainsList as $key => $sub_domain) {
$mem->su($sub_domain["cuid"]);
// Check if we already have a valid cert for this domain (valid for more than $VALID_DAYS days
// Either the subdomain (first, quicker), or any Certificate found for this FQDN
if (isset($sub_domain['sub_domain']["certificate_id"])) {

// trick below: false=>not found, 0 => Snakeoil == skip both
if ( $current = $ssl->get_certificate($sub_domain["sub_domain"]["certificate_id"],true) ) {

// found, is it valid ? (fqdn match) (skips panel one)
if ($ssl->fqdnmatch($current["fqdn"],$sub_domain["sub_domain"]["fqdn"])) {
// found and valid, (works for wildcards too ;) )
// now what about the date?
$t = time();
if ($current['validstartts'] < $t &&
$t < ($current['validendts'] - $VALID_DIFF)) {
// currently valid, and valid for more than $VALID_DAYS
// let's skip this one for now
continue;
}
}
}
}

// not found or invalid or expired soon, let's get one:
vprint( _("\r$spacer\rRequesting domain %d/%d: %s"), array( $key + 1, count( $domainsList),$sub_domain["sub_domain"]["fqdn"] ));
if( ! $certbot->isLocalAlterncDomain( $sub_domain["sub_domain"]["fqdn"] ) ){
continue;
}
vprint( _(" hosted locally, running certbot..."), array( ));
$certbot->import($sub_domain["sub_domain"]["fqdn"]);
}

// not found or invalid or expired soon, let's get one:
vprint( _("\r$spacer\rRequesting domain %d/%d: %s"), array( $key + 1, count( $domainsList),$sub_domain["sub_domain"]["fqdn"] ));
if( ! $certbot->isLocalAlterncDomain( $sub_domain["sub_domain"]["fqdn"] ) ){
continue;
}
vprint( _(" hosted locally, running certbot..."), array( ));

$certbot->import($sub_domain["sub_domain"]["fqdn"]);
vprint( _("\nFinished Certbot renewal for non-system certificates"), count( $domainsList ));
} else {
vprint( _("\nNo standard Certbot renewal for non-system-certificates"), count( $domainsList ));
}
vprint( _("\nFinished Certbot renewal, now doing system certs\n"), count( $domainsList ));
} else {
vprint( _("\nNo standard Certbot renewal to do, now doing system certs\n"), count( $domainsList ));
}
else {
vprint(_("Skipping non-system certificates, requested certificates type: %s"), array($REQUEST_CERTS));
}

vprint( _("\nFinished Certbot renewal\n"), count( $domainsList ));
vprint( _("\nFinished Certbot renewal\n"), array());
14 changes: 13 additions & 1 deletion src/usr/lib/alternc/install.d/alternc-certbot
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,24 @@ if [[ " $@ " =~ " --quiet " ]] ; then
VERBOSE=''
fi

# Set the default value to use if it isn't set.
if [ -z "$ALTERNC_REQUEST_CERTIFICATES" ] ; then
ALTERNC_REQUEST_CERTIFICATES="all"
fi

# Leave which certificates are requested up to the environments variables,
# unless "--all" is passed.
CERTS=""
if [[ " $@ " =~ " --all " ]] ; then
CERTS="--certificates all"
fi

if [ "$1" == "apache2" ]; then

if [ ! -d /var/lib/letsencrypt/ ]; then
mkdir /var/lib/letsencrypt/
fi

##Generate let's encrypt certificate
/usr/lib/alternc/generate_certbot.php "$VERBOSE"
ALTERNC_REQUEST_CERTIFICATES="$ALTERNC_REQUEST_CERTIFICATES" /usr/lib/alternc/generate_certbot.php "$VERBOSE" "$CERTS"
fi

0 comments on commit fc93ca9

Please sign in to comment.