1#!/usr/bin/php
2<?php
3
4use splitbrain\phpcli\Options;
5
6if(!defined('DOKU_INC')) define('DOKU_INC', realpath(__DIR__ . '/../../../') . '/');
7define('NOSESSION', 1);
8require_once(DOKU_INC . 'inc/init.php');
9
10class LetsEncrypt extends DokuWiki_CLI_Plugin {
11
12    /** @var helper_plugin_letsencrypt $helper */
13    protected $helper;
14
15    /**
16     * LetsEncrypt constructor.
17     */
18    public function __construct() {
19        parent::__construct();
20        $this->helper = plugin_load('helper', 'letsencrypt');
21    }
22
23    /**
24     * Register options and arguments on the given $options object
25     *
26     * @param DokuCLI_Options $options
27     * @return void
28     */
29    protected function setup(Options $options) {
30        $options->setHelp(
31            'This is a command line interface to the letsencrypt plugin. It allows renewing ' .
32            'certificates from cron jobs etc.' . "\n" .
33            'When run without any options, it lists all domains and their certificate status'
34        );
35
36        $options->registerOption('update', 'Update the certificates', 'u');
37        $options->registerOption('force', 'Force a certificate update even when none is needed', 'f');
38        $options->registerOption('run-on-update', 'Run this command when the certificate has been updated', 'r', 'command');
39        $options->registerOption('quiet', 'Do not print anything except fatal errors (and whatever the run-on-update program outputs)', 'q');
40    }
41
42    /**
43     * Your main program
44     *
45     * Arguments and options have been parsed when this is run
46     *
47     * @param DokuCLI_Options $options
48     * @return void
49     */
50    protected function main(Options $options) {
51        if(!$this->helper->getRoot()) $this->fatal('no webserver root directory set or detected');
52        if(!$this->helper->getCertDir()) $this->fatal('no certificate directory set');
53        if(!$this->helper->hasAccount()) $this->fatal('no letsencrypt account set up, yet');
54
55        $quiet = $options->getOpt('quiet');
56
57        $domains = $this->helper->getAllDomains();
58        if(!$quiet) $this->printDomains($domains);
59
60        if($options->getOpt('update')) {
61            if(!$options->getOpt('force') && !$this->updateNeeded($domains)) {
62                if(!$quiet) $this->success('No update needed');
63                exit(0);
64            }
65
66            if(!$quiet) $this->helper->setCliLogger($this);
67            $this->helper->updateCerts();
68            if($options->getOpt('run-on-update')) {
69                passthru($options->getOpt('run-on-update'), $return);
70                exit($return);
71            }
72        }
73    }
74
75    /**
76     * @param $domains
77     * @return bool
78     */
79    protected function updateNeeded($domains) {
80        foreach($domains as $domain => $expire) {
81            if($expire < 31) return true;
82        }
83        return false;
84    }
85
86    /**
87     * list all the domains
88     * @param $domains
89     */
90    protected function printDomains($domains) {
91        foreach($domains as $domain => $expire) {
92            if($expire > 30) {
93                $this->colors->ptln(sprintf("%-50s" . $this->helper->getLang('valid'), $domain, $expire), 'green');
94            } elseif($expire == 0) {
95                $this->colors->ptln(sprintf("%-50s" . $this->helper->getLang('invalid'), $domain), 'red');
96            } else {
97                $this->colors->ptln(sprintf("%-50s" . $this->helper->getLang('valid'), $domain, $expire), 'yellow');
98            }
99        }
100    }
101}
102
103$le = new LetsEncrypt();
104$le->run();
105