From 68489fde52612fd9e8f19493bb509f67f2acf756 Mon Sep 17 00:00:00 2001 From: Phil Kunz Date: Wed, 22 Jun 2016 13:09:18 +0200 Subject: [PATCH] now working --- README.md | 2 - .../account_key.pem | 51 + .../registration_info.json | 12 + .../certs/sub2.bleu.de/cert-1466593547.csr | 27 + .../certs/sub2.bleu.de/cert-1466593547.pem | 34 + dist/assets/certs/sub2.bleu.de/cert.csr | 1 + dist/assets/certs/sub2.bleu.de/cert.pem | 1 + .../certs/sub2.bleu.de/chain-1466593547.pem | 27 + dist/assets/certs/sub2.bleu.de/chain.pem | 1 + .../sub2.bleu.de/fullchain-1466593547.pem | 61 + dist/assets/certs/sub2.bleu.de/fullchain.pem | 1 + .../certs/sub2.bleu.de/privkey-1466593547.pem | 51 + dist/assets/certs/sub2.bleu.de/privkey.pem | 1 + dist/assets/config.json | 1 + dist/assets/letsencrypt.sh | 1054 +++++++++++++++++ dist/cert.hook.d.ts | 1 + dist/cert.hook.js | 50 +- dist/cert.paths.d.ts | 5 +- dist/cert.paths.js | 8 +- dist/cert.plugins.d.ts | 10 + dist/cert.plugins.js | 14 +- dist/index.d.ts | 2 +- dist/index.js | 17 +- dist/install.d.ts | 1 + dist/install.js | 28 +- package.json | 9 +- test/test.js | 31 +- test/test.ts | 33 +- ts/cert.hook.ts | 59 +- ts/cert.paths.ts | 6 +- ts/cert.plugins.ts | 5 + ts/index.ts | 15 +- ts/install.ts | 34 +- 33 files changed, 1610 insertions(+), 43 deletions(-) create mode 100644 dist/assets/accounts/aHR0cHM6Ly9hY21lLXYwMS5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeQo/account_key.pem create mode 100644 dist/assets/accounts/aHR0cHM6Ly9hY21lLXYwMS5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeQo/registration_info.json create mode 100644 dist/assets/certs/sub2.bleu.de/cert-1466593547.csr create mode 100644 dist/assets/certs/sub2.bleu.de/cert-1466593547.pem create mode 120000 dist/assets/certs/sub2.bleu.de/cert.csr create mode 120000 dist/assets/certs/sub2.bleu.de/cert.pem create mode 100644 dist/assets/certs/sub2.bleu.de/chain-1466593547.pem create mode 120000 dist/assets/certs/sub2.bleu.de/chain.pem create mode 100644 dist/assets/certs/sub2.bleu.de/fullchain-1466593547.pem create mode 120000 dist/assets/certs/sub2.bleu.de/fullchain.pem create mode 100644 dist/assets/certs/sub2.bleu.de/privkey-1466593547.pem create mode 120000 dist/assets/certs/sub2.bleu.de/privkey.pem create mode 100644 dist/assets/config.json create mode 100755 dist/assets/letsencrypt.sh mode change 100644 => 100755 dist/cert.hook.js diff --git a/README.md b/README.md index 14df2d0..7dfd7cb 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # Cert Easily obain SSL certificates from LetsEncrypt. Supports DNS-01 challenge. TypeScript ready. -> Note: this package is in pre-alpha stage and will be ready soon. - ## Usage ```typescript diff --git a/dist/assets/accounts/aHR0cHM6Ly9hY21lLXYwMS5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeQo/account_key.pem b/dist/assets/accounts/aHR0cHM6Ly9hY21lLXYwMS5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeQo/account_key.pem new file mode 100644 index 0000000..0f94f80 --- /dev/null +++ b/dist/assets/accounts/aHR0cHM6Ly9hY21lLXYwMS5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeQo/account_key.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/dist/assets/accounts/aHR0cHM6Ly9hY21lLXYwMS5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeQo/registration_info.json b/dist/assets/accounts/aHR0cHM6Ly9hY21lLXYwMS5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeQo/registration_info.json new file mode 100644 index 0000000..644eab9 --- /dev/null +++ b/dist/assets/accounts/aHR0cHM6Ly9hY21lLXYwMS5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeQo/registration_info.json @@ -0,0 +1,12 @@ +{ + "id": 2299055, + "key": { + "kty": "RSA", + "n": "0TfTunO8-B7kMI6lriNap3c-ACAk7qQXeRYXUbRoyZbU9hKI_BACk-4htPc-5pOICVT7gbaErhsOzIQRKrp1flC7JQSol1PNWe57cMD9IecdhtcxJq1HMFqyF5JQ9MZxSnyp03QdAUVVev23T7qA24Z0HK8jltt5K4TvAqid0M0nQ6sAM0LF7l6frQDckIoYcZ_3pxW5U7JewUBAyFSQpzKOSmf2GeyLZn0SZr0w82H5yO81NNx6FmR653zLXqj4CGjvC4uHvf-5lwSmnqlhCv2dlgtuLVm5j5YV8wmiWvElkrQrnCNaCEVYe1qhIHBASQtkmDGBztykIUatC4p7lVn0aUvUi9Qdzh_HcqbBuCBxZb57TWmWxiYXS9vTEM06fAYBlAuP-GN38v_IkJWRmJxDDTssfWCVVgotJQjQB2tzs301TG1RLu1moN-Qz27FaV-bGR8sV3l2eLY5K5Xp_QCt1j9Xm-4dDFfmS-eBf8l4XK7-Kx87UTLGDgQp-mMktmF0S9oYsZeHOwNsIhDlzz4QnTyEy-ihn26ctS67RcJmmyTPYEhBPh2Ajg7Hu8KsyKnJyzmcA8NeC9bEbeNdOwq6C8kMKiYks21oHkC2VeYkhTnRkan_RaG6L0xkHyiLwd-QbFDtE8vC763_V20y09syvj6nka2L3XpwT0nafJE", + "e": "AQAB" + }, + "contact": [], + "agreement": "https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf", + "initialIp": "87.178.79.88", + "createdAt": "2016-06-22T11:05:47.509440404Z" +} \ No newline at end of file diff --git a/dist/assets/certs/sub2.bleu.de/cert-1466593547.csr b/dist/assets/certs/sub2.bleu.de/cert-1466593547.csr new file mode 100644 index 0000000..f83a911 --- /dev/null +++ b/dist/assets/certs/sub2.bleu.de/cert-1466593547.csr @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEhjCCAm4CAQAwFzEVMBMGA1UEAwwMc3ViMi5ibGV1LmRlMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAzNcXBGWjnR/m07vwYgjV5cm3foKZNM3MjYQP +0a7vmXN4Yd+1TrVyso18HNkjkia+pzYoTEuLYYZmqIXF/wKRc8E2joRYYr9m636d +8lbWjFZXC2GIOZfhgPghDWl8/okaExpqTcG7BRwffIbAqmgFIWSXMNlUbQuGCVPr +EkSMPODLuEukj14XpEIxiqMFQxTnXODKj/rJNZJDSJ1QHr5cCskgOO4NKmgmybyK +2K0CzNmaIjw4iTOSJL4vhmhKolFvsZoXpE41S1QZAc9dmafvs1yKYsKIjGfmDUlu +nOKL2o5eJuUaHiI54B7QRa1hBwaelXLUgiIRQpzv5m8/vpkMdq2jxeq68OlG8hyy +8Bm2+HkzgtHju8u+/nNKLEcF7fx4Irs6xKJdFJDwoVTckNOY10kGImVoy0HKo/8B +k34A/f16H7pS9hFDe5jUUiEIHY7ufoBZkOgEZn1WwdBw5Sb5gTJQq9qxfB9ai7+1 +Th76dLq0okBoXR4d0ttn3oNyWEF2/nubd0lEw71PE4WJMXGYtpyV+hklipzHXS5w +dxQtkhZLgGr/RuIz/N4wiHsVZfxkIPzKfq4Nc9RoRllsSqG/7wl96gaLVwn/P9N6 +GIXJ0TX+S0uuujBx/8KeZKnBNXN/FzTjBg4D9QQfKzL/50OqFkGvjax6EDACYh4/ +WBybMocCAwEAAaAqMCgGCSqGSIb3DQEJDjEbMBkwFwYDVR0RBBAwDoIMc3ViMi5i +bGV1LmRlMA0GCSqGSIb3DQEBCwUAA4ICAQBWl8iKxLq+9YcL8q5adVUGQyLEJh5q +hTxNMQipIR3NzltQAjhp3QFLOMILWCb/4loOEC5CfeFjo6SqzkjnCSi4cljf3r5q +aYoJUujq62mrnm0L/kTSIWpo3jJXbSdnfZhVFDbTeykrB+SHwhRgRHTp2q7bsFRy +EovDb1m1pImwtULFNZ3xFaDCGRzs8tJTGlTD+dMxWeo47h2odnMYBH9eL1pPIVR9 +ntFUwJ+XYgiMVvx2g6HrhhfLiOf3tp/HFuBtyWs+i7MONsLYoc/oKNvZyx7yL3/7 +0w5daTAHdqrYUFXM/vKANqvmB3RKsOIJTtxAorEgVuo2ErtzCT8fPXYowpgT4wxi +aR1kQSJyn8kDkVkMz026BL12VpodDEJRSHb3wB0yg3Fkz1v4ECWA5C4c3Q/54avY +g+9ykjMZpSQWQs3XOYQ+YHxboUq8KY4El+M6FV/SGaED+wY7pxitXqP4AHaHMLxV +54VwUxYTFtQ/3m+QETdA6wXwmqd42of+CdQIipMHUea0aTS0k0ozGFMzmZJSlx1A +zJ0VTy2FqReucLe5nUFLO+8rdQI06aknfOdumuUL8guWLV9/bCDnIIxurkjGXs04 +WiyUsQ9xA9tn51Gg8tRw8I0tBrXe4xCtrvHkV/Je/33NYqUVrAGXDILpG9WRlSPi +iy6iA5oEiT4CVg== +-----END CERTIFICATE REQUEST----- diff --git a/dist/assets/certs/sub2.bleu.de/cert-1466593547.pem b/dist/assets/certs/sub2.bleu.de/cert-1466593547.pem new file mode 100644 index 0000000..b7ca7ec --- /dev/null +++ b/dist/assets/certs/sub2.bleu.de/cert-1466593547.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF/DCCBOSgAwIBAgISA7oA26pZemK7hGOH71u39RkMMA0GCSqGSIb3DQEBCwUA +MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD +ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNjA2MjIxMDA2MDBaFw0x +NjA5MjAxMDA2MDBaMBcxFTATBgNVBAMTDHN1YjIuYmxldS5kZTCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAMzXFwRlo50f5tO78GII1eXJt36CmTTNzI2E +D9Gu75lzeGHftU61crKNfBzZI5Imvqc2KExLi2GGZqiFxf8CkXPBNo6EWGK/Zut+ +nfJW1oxWVwthiDmX4YD4IQ1pfP6JGhMaak3BuwUcH3yGwKpoBSFklzDZVG0LhglT +6xJEjDzgy7hLpI9eF6RCMYqjBUMU51zgyo/6yTWSQ0idUB6+XArJIDjuDSpoJsm8 +ititAszZmiI8OIkzkiS+L4ZoSqJRb7GaF6RONUtUGQHPXZmn77NcimLCiIxn5g1J +bpzii9qOXiblGh4iOeAe0EWtYQcGnpVy1IIiEUKc7+ZvP76ZDHato8XquvDpRvIc +svAZtvh5M4LR47vLvv5zSixHBe38eCK7OsSiXRSQ8KFU3JDTmNdJBiJlaMtByqP/ +AZN+AP39eh+6UvYRQ3uY1FIhCB2O7n6AWZDoBGZ9VsHQcOUm+YEyUKvasXwfWou/ +tU4e+nS6tKJAaF0eHdLbZ96DclhBdv57m3dJRMO9TxOFiTFxmLaclfoZJYqcx10u +cHcULZIWS4Bq/0biM/zeMIh7FWX8ZCD8yn6uDXPUaEZZbEqhv+8JfeoGi1cJ/z/T +ehiFydE1/ktLrrowcf/CnmSpwTVzfxc04wYOA/UEHysy/+dDqhZBr42sehAwAmIe +P1gcmzKHAgMBAAGjggINMIICCTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI +KwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFPW5umA7 +cYewAhF8NtPtXBzpxsYMMB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyh +MHAGCCsGAQUFBwEBBGQwYjAvBggrBgEFBQcwAYYjaHR0cDovL29jc3AuaW50LXgz +LmxldHNlbmNyeXB0Lm9yZy8wLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14 +My5sZXRzZW5jcnlwdC5vcmcvMBcGA1UdEQQQMA6CDHN1YjIuYmxldS5kZTCB/gYD +VR0gBIH2MIHzMAgGBmeBDAECATCB5gYLKwYBBAGC3xMBAQEwgdYwJgYIKwYBBQUH +AgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5cHQub3JnMIGrBggrBgEFBQcCAjCBngyB +m1RoaXMgQ2VydGlmaWNhdGUgbWF5IG9ubHkgYmUgcmVsaWVkIHVwb24gYnkgUmVs +eWluZyBQYXJ0aWVzIGFuZCBvbmx5IGluIGFjY29yZGFuY2Ugd2l0aCB0aGUgQ2Vy +dGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0IGh0dHBzOi8vbGV0c2VuY3J5cHQub3Jn +L3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQBWqCXn4owhpx5uQqC0Cfu4 +XsNzJGETrevfV51nMsw5YE3+dHW5B3Kx9Bea0gsc1eue7z0sPsIjGxJD1ZxIOJHj +b0I29ZxdCGUyG4mjYEQv/+l6iq8HSUYnhl1HTLOCV2zPrXd8YO8vmyqVNq04QgN/ +SBedabrHK1nTf5Hi3vjIAx78/WgOYA6XayyX1Ef1wRtmSbNtsDP9EHh8zmMu67Yr +0D0OHCKMShVAkXtavi5ALAN28ZZTbhQ5iGlJZKP2o3Cp1tDc7491oqSQ0rATgSJi +vBRC8QGTE8igdo2oUT9Vo4orfWYw4U9/8kTQ3E1VOaMJNPa7esUUSuMrLFJ+xWeu +-----END CERTIFICATE----- diff --git a/dist/assets/certs/sub2.bleu.de/cert.csr b/dist/assets/certs/sub2.bleu.de/cert.csr new file mode 120000 index 0000000..8c86cf6 --- /dev/null +++ b/dist/assets/certs/sub2.bleu.de/cert.csr @@ -0,0 +1 @@ +cert-1466593547.csr \ No newline at end of file diff --git a/dist/assets/certs/sub2.bleu.de/cert.pem b/dist/assets/certs/sub2.bleu.de/cert.pem new file mode 120000 index 0000000..3bbb5fa --- /dev/null +++ b/dist/assets/certs/sub2.bleu.de/cert.pem @@ -0,0 +1 @@ +cert-1466593547.pem \ No newline at end of file diff --git a/dist/assets/certs/sub2.bleu.de/chain-1466593547.pem b/dist/assets/certs/sub2.bleu.de/chain-1466593547.pem new file mode 100644 index 0000000..0002462 --- /dev/null +++ b/dist/assets/certs/sub2.bleu.de/chain-1466593547.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow +SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT +GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF +q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 +SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 +Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA +a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj +/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG +CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv +bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k +c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw +VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC +ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz +MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu +Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF +AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo +uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ +wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu +X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG +PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 +KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== +-----END CERTIFICATE----- diff --git a/dist/assets/certs/sub2.bleu.de/chain.pem b/dist/assets/certs/sub2.bleu.de/chain.pem new file mode 120000 index 0000000..166af3c --- /dev/null +++ b/dist/assets/certs/sub2.bleu.de/chain.pem @@ -0,0 +1 @@ +chain-1466593547.pem \ No newline at end of file diff --git a/dist/assets/certs/sub2.bleu.de/fullchain-1466593547.pem b/dist/assets/certs/sub2.bleu.de/fullchain-1466593547.pem new file mode 100644 index 0000000..6880571 --- /dev/null +++ b/dist/assets/certs/sub2.bleu.de/fullchain-1466593547.pem @@ -0,0 +1,61 @@ +-----BEGIN CERTIFICATE----- +MIIF/DCCBOSgAwIBAgISA7oA26pZemK7hGOH71u39RkMMA0GCSqGSIb3DQEBCwUA +MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD +ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNjA2MjIxMDA2MDBaFw0x +NjA5MjAxMDA2MDBaMBcxFTATBgNVBAMTDHN1YjIuYmxldS5kZTCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAMzXFwRlo50f5tO78GII1eXJt36CmTTNzI2E +D9Gu75lzeGHftU61crKNfBzZI5Imvqc2KExLi2GGZqiFxf8CkXPBNo6EWGK/Zut+ +nfJW1oxWVwthiDmX4YD4IQ1pfP6JGhMaak3BuwUcH3yGwKpoBSFklzDZVG0LhglT +6xJEjDzgy7hLpI9eF6RCMYqjBUMU51zgyo/6yTWSQ0idUB6+XArJIDjuDSpoJsm8 +ititAszZmiI8OIkzkiS+L4ZoSqJRb7GaF6RONUtUGQHPXZmn77NcimLCiIxn5g1J +bpzii9qOXiblGh4iOeAe0EWtYQcGnpVy1IIiEUKc7+ZvP76ZDHato8XquvDpRvIc +svAZtvh5M4LR47vLvv5zSixHBe38eCK7OsSiXRSQ8KFU3JDTmNdJBiJlaMtByqP/ +AZN+AP39eh+6UvYRQ3uY1FIhCB2O7n6AWZDoBGZ9VsHQcOUm+YEyUKvasXwfWou/ +tU4e+nS6tKJAaF0eHdLbZ96DclhBdv57m3dJRMO9TxOFiTFxmLaclfoZJYqcx10u +cHcULZIWS4Bq/0biM/zeMIh7FWX8ZCD8yn6uDXPUaEZZbEqhv+8JfeoGi1cJ/z/T +ehiFydE1/ktLrrowcf/CnmSpwTVzfxc04wYOA/UEHysy/+dDqhZBr42sehAwAmIe +P1gcmzKHAgMBAAGjggINMIICCTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI +KwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFPW5umA7 +cYewAhF8NtPtXBzpxsYMMB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyh +MHAGCCsGAQUFBwEBBGQwYjAvBggrBgEFBQcwAYYjaHR0cDovL29jc3AuaW50LXgz +LmxldHNlbmNyeXB0Lm9yZy8wLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14 +My5sZXRzZW5jcnlwdC5vcmcvMBcGA1UdEQQQMA6CDHN1YjIuYmxldS5kZTCB/gYD +VR0gBIH2MIHzMAgGBmeBDAECATCB5gYLKwYBBAGC3xMBAQEwgdYwJgYIKwYBBQUH +AgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5cHQub3JnMIGrBggrBgEFBQcCAjCBngyB +m1RoaXMgQ2VydGlmaWNhdGUgbWF5IG9ubHkgYmUgcmVsaWVkIHVwb24gYnkgUmVs +eWluZyBQYXJ0aWVzIGFuZCBvbmx5IGluIGFjY29yZGFuY2Ugd2l0aCB0aGUgQ2Vy +dGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0IGh0dHBzOi8vbGV0c2VuY3J5cHQub3Jn +L3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQBWqCXn4owhpx5uQqC0Cfu4 +XsNzJGETrevfV51nMsw5YE3+dHW5B3Kx9Bea0gsc1eue7z0sPsIjGxJD1ZxIOJHj +b0I29ZxdCGUyG4mjYEQv/+l6iq8HSUYnhl1HTLOCV2zPrXd8YO8vmyqVNq04QgN/ +SBedabrHK1nTf5Hi3vjIAx78/WgOYA6XayyX1Ef1wRtmSbNtsDP9EHh8zmMu67Yr +0D0OHCKMShVAkXtavi5ALAN28ZZTbhQ5iGlJZKP2o3Cp1tDc7491oqSQ0rATgSJi +vBRC8QGTE8igdo2oUT9Vo4orfWYw4U9/8kTQ3E1VOaMJNPa7esUUSuMrLFJ+xWeu +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow +SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT +GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF +q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 +SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 +Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA +a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj +/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG +CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv +bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k +c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw +VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC +ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz +MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu +Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF +AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo +uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ +wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu +X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG +PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 +KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== +-----END CERTIFICATE----- diff --git a/dist/assets/certs/sub2.bleu.de/fullchain.pem b/dist/assets/certs/sub2.bleu.de/fullchain.pem new file mode 120000 index 0000000..fd23815 --- /dev/null +++ b/dist/assets/certs/sub2.bleu.de/fullchain.pem @@ -0,0 +1 @@ +fullchain-1466593547.pem \ No newline at end of file diff --git a/dist/assets/certs/sub2.bleu.de/privkey-1466593547.pem b/dist/assets/certs/sub2.bleu.de/privkey-1466593547.pem new file mode 100644 index 0000000..be9e789 --- /dev/null +++ b/dist/assets/certs/sub2.bleu.de/privkey-1466593547.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/dist/assets/certs/sub2.bleu.de/privkey.pem b/dist/assets/certs/sub2.bleu.de/privkey.pem new file mode 120000 index 0000000..d9d6135 --- /dev/null +++ b/dist/assets/certs/sub2.bleu.de/privkey.pem @@ -0,0 +1 @@ +privkey-1466593547.pem \ No newline at end of file diff --git a/dist/assets/config.json b/dist/assets/config.json new file mode 100644 index 0000000..ec9e221 --- /dev/null +++ b/dist/assets/config.json @@ -0,0 +1 @@ +{"cfEmail":"sandbox@lossless.digital","cfKey":"5108a833dced8e8bd7186ae5833855b0dc138"} \ No newline at end of file diff --git a/dist/assets/letsencrypt.sh b/dist/assets/letsencrypt.sh new file mode 100755 index 0000000..4efa570 --- /dev/null +++ b/dist/assets/letsencrypt.sh @@ -0,0 +1,1054 @@ +#!/usr/bin/env bash + +# letsencrypt.sh by lukas2511 +# Source: https://github.com/lukas2511/letsencrypt.sh +# +# This script is licensed under The MIT License (see LICENSE for more information). + +set -e +set -u +set -o pipefail +[[ -n "${ZSH_VERSION:-}" ]] && set -o SH_WORD_SPLIT && set +o FUNCTION_ARGZERO +umask 077 # paranoid umask, we're creating private keys + +# Find directory in which this script is stored by traversing all symbolic links +SOURCE="${0}" +while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located +done +SCRIPTDIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +BASEDIR="${SCRIPTDIR}" + +# Create (identifiable) temporary files +_mktemp() { + # shellcheck disable=SC2068 + mktemp ${@:-} "${TMPDIR:-/tmp}/letsencrypt.sh-XXXXXX" +} + +# Check for script dependencies +check_dependencies() { + # just execute some dummy and/or version commands to see if required tools exist and are actually usable + openssl version > /dev/null 2>&1 || _exiterr "This script requires an openssl binary." + _sed "" < /dev/null > /dev/null 2>&1 || _exiterr "This script requires sed with support for extended (modern) regular expressions." + command -v grep > /dev/null 2>&1 || _exiterr "This script requires grep." + _mktemp -u > /dev/null 2>&1 || _exiterr "This script requires mktemp." + diff -u /dev/null /dev/null || _exiterr "This script requires diff." + + # curl returns with an error code in some ancient versions so we have to catch that + set +e + curl -V > /dev/null 2>&1 + retcode="$?" + set -e + if [[ ! "${retcode}" = "0" ]] && [[ ! "${retcode}" = "2" ]]; then + _exiterr "This script requires curl." + fi +} + +store_configvars() { + __KEY_ALGO="${KEY_ALGO}" + __OCSP_MUST_STAPLE="${OCSP_MUST_STAPLE}" + __PRIVATE_KEY_RENEW="${PRIVATE_KEY_RENEW}" + __KEYSIZE="${KEYSIZE}" + __CHALLENGETYPE="${CHALLENGETYPE}" + __HOOK="${HOOK}" + __WELLKNOWN="${WELLKNOWN}" + __HOOK_CHAIN="${HOOK_CHAIN}" + __OPENSSL_CNF="${OPENSSL_CNF}" + __RENEW_DAYS="${RENEW_DAYS}" +} + +reset_configvars() { + KEY_ALGO="${__KEY_ALGO}" + OCSP_MUST_STAPLE="${__OCSP_MUST_STAPLE}" + PRIVATE_KEY_RENEW="${__PRIVATE_KEY_RENEW}" + KEYSIZE="${__KEYSIZE}" + CHALLENGETYPE="${__CHALLENGETYPE}" + HOOK="${__HOOK}" + WELLKNOWN="${__WELLKNOWN}" + HOOK_CHAIN="${__HOOK_CHAIN}" + OPENSSL_CNF="${__OPENSSL_CNF}" + RENEW_DAYS="${__RENEW_DAYS}" +} + +# verify configuration values +verify_config() { + [[ "${CHALLENGETYPE}" =~ (http-01|dns-01) ]] || _exiterr "Unknown challenge type ${CHALLENGETYPE}... can not continue." + if [[ "${CHALLENGETYPE}" = "dns-01" ]] && [[ -z "${HOOK}" ]]; then + _exiterr "Challenge type dns-01 needs a hook script for deployment... can not continue." + fi + if [[ "${CHALLENGETYPE}" = "http-01" && ! -d "${WELLKNOWN}" ]]; then + _exiterr "WELLKNOWN directory doesn't exist, please create ${WELLKNOWN} and set appropriate permissions." + fi + [[ "${KEY_ALGO}" =~ ^(rsa|prime256v1|secp384r1)$ ]] || _exiterr "Unknown public key algorithm ${KEY_ALGO}... can not continue." +} + +# Setup default config values, search for and load configuration files +load_config() { + # Check for config in various locations + if [[ -z "${CONFIG:-}" ]]; then + for check_config in "/etc/letsencrypt.sh" "/usr/local/etc/letsencrypt.sh" "${PWD}" "${SCRIPTDIR}"; do + if [[ -f "${check_config}/config" ]]; then + BASEDIR="${check_config}" + CONFIG="${check_config}/config" + break + fi + done + fi + + # Default values + CA="https://acme-v01.api.letsencrypt.org/directory" + LICENSE="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf" + CERTDIR= + ACCOUNTDIR= + CHALLENGETYPE="http-01" + CONFIG_D= + DOMAINS_TXT= + HOOK= + HOOK_CHAIN="no" + RENEW_DAYS="30" + KEYSIZE="4096" + WELLKNOWN= + PRIVATE_KEY_RENEW="yes" + KEY_ALGO=rsa + OPENSSL_CNF="$(openssl version -d | cut -d\" -f2)/openssl.cnf" + CONTACT_EMAIL= + LOCKFILE= + OCSP_MUST_STAPLE="no" + + if [[ -z "${CONFIG:-}" ]]; then + echo "#" >&2 + echo "# !! WARNING !! No main config file found, using default config!" >&2 + echo "#" >&2 + elif [[ -f "${CONFIG}" ]]; then + echo "# INFO: Using main config file ${CONFIG}" + BASEDIR="$(dirname "${CONFIG}")" + # shellcheck disable=SC1090 + . "${CONFIG}" + else + _exiterr "Specified config file doesn't exist." + fi + + if [[ -n "${CONFIG_D}" ]]; then + if [[ ! -d "${CONFIG_D}" ]]; then + _exiterr "The path ${CONFIG_D} specified for CONFIG_D does not point to a directory." >&2 + fi + + for check_config_d in "${CONFIG_D}"/*.sh; do + if [[ ! -e "${check_config_d}" ]]; then + echo "# !! WARNING !! Extra configuration directory ${CONFIG_D} exists, but no configuration found in it." >&2 + break + elif [[ -f "${check_config_d}" ]] && [[ -r "${check_config_d}" ]]; then + echo "# INFO: Using additional config file ${check_config_d}" + # shellcheck disable=SC1090 + . "${check_config_d}" + else + _exiterr "Specified additional config ${check_config_d} is not readable or not a file at all." >&2 + fi + done + fi + + # Remove slash from end of BASEDIR. Mostly for cleaner outputs, doesn't change functionality. + BASEDIR="${BASEDIR%%/}" + + # Check BASEDIR and set default variables + [[ -d "${BASEDIR}" ]] || _exiterr "BASEDIR does not exist: ${BASEDIR}" + + CAHASH="$(echo "${CA}" | urlbase64)" + [[ -z "${ACCOUNTDIR}" ]] && ACCOUNTDIR="${BASEDIR}/accounts" + mkdir -p "${ACCOUNTDIR}/${CAHASH}" + [[ -f "${ACCOUNTDIR}/${CAHASH}/config" ]] && . "${ACCOUNTDIR}/${CAHASH}/config" + ACCOUNT_KEY="${ACCOUNTDIR}/${CAHASH}/account_key.pem" + ACCOUNT_KEY_JSON="${ACCOUNTDIR}/${CAHASH}/registration_info.json" + + if [[ -f "${BASEDIR}/private_key.pem" ]] && [[ ! -f "${ACCOUNT_KEY}" ]]; then + echo "! Moving private_key.pem to ${ACCOUNT_KEY}" + mv "${BASEDIR}/private_key.pem" "${ACCOUNT_KEY}" + fi + if [[ -f "${BASEDIR}/private_key.json" ]] && [[ ! -f "${ACCOUNT_KEY_JSON}" ]]; then + echo "! Moving private_key.json to ${ACCOUNT_KEY_JSON}" + mv "${BASEDIR}/private_key.json" "${ACCOUNT_KEY_JSON}" + fi + + [[ -z "${CERTDIR}" ]] && CERTDIR="${BASEDIR}/certs" + [[ -z "${DOMAINS_TXT}" ]] && DOMAINS_TXT="${BASEDIR}/domains.txt" + [[ -z "${WELLKNOWN}" ]] && WELLKNOWN="${BASEDIR}/.acme-challenges" + [[ -z "${LOCKFILE}" ]] && LOCKFILE="${BASEDIR}/lock" + + [[ -n "${PARAM_HOOK:-}" ]] && HOOK="${PARAM_HOOK}" + [[ -n "${PARAM_CERTDIR:-}" ]] && CERTDIR="${PARAM_CERTDIR}" + [[ -n "${PARAM_CHALLENGETYPE:-}" ]] && CHALLENGETYPE="${PARAM_CHALLENGETYPE}" + [[ -n "${PARAM_KEY_ALGO:-}" ]] && KEY_ALGO="${PARAM_KEY_ALGO}" + [[ -n "${PARAM_OCSP_MUST_STAPLE:-}" ]] && OCSP_MUST_STAPLE="${PARAM_OCSP_MUST_STAPLE}" + + verify_config + store_configvars +} + +# Initialize system +init_system() { + load_config + + # Lockfile handling (prevents concurrent access) + LOCKDIR="$(dirname "${LOCKFILE}")" + [[ -w "${LOCKDIR}" ]] || _exiterr "Directory ${LOCKDIR} for LOCKFILE ${LOCKFILE} is not writable, aborting." + ( set -C; date > "${LOCKFILE}" ) 2>/dev/null || _exiterr "Lock file '${LOCKFILE}' present, aborting." + remove_lock() { rm -f "${LOCKFILE}"; } + trap 'remove_lock' EXIT + + # Get CA URLs + CA_DIRECTORY="$(http_request get "${CA}")" + CA_NEW_CERT="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value new-cert)" && + CA_NEW_AUTHZ="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value new-authz)" && + CA_NEW_REG="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value new-reg)" && + # shellcheck disable=SC2015 + CA_REVOKE_CERT="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value revoke-cert)" || + _exiterr "Problem retrieving ACME/CA-URLs, check if your configured CA points to the directory entrypoint." + + # Export some environment variables to be used in hook script + export WELLKNOWN BASEDIR CERTDIR CONFIG + + # Checking for private key ... + register_new_key="no" + if [[ -n "${PARAM_ACCOUNT_KEY:-}" ]]; then + # a private key was specified from the command line so use it for this run + echo "Using private key ${PARAM_ACCOUNT_KEY} instead of account key" + ACCOUNT_KEY="${PARAM_ACCOUNT_KEY}" + ACCOUNT_KEY_JSON="${PARAM_ACCOUNT_KEY}.json" + else + # Check if private account key exists, if it doesn't exist yet generate a new one (rsa key) + if [[ ! -e "${ACCOUNT_KEY}" ]]; then + echo "+ Generating account key..." + _openssl genrsa -out "${ACCOUNT_KEY}" "${KEYSIZE}" + register_new_key="yes" + fi + fi + openssl rsa -in "${ACCOUNT_KEY}" -check 2>/dev/null > /dev/null || _exiterr "Account key is not valid, can not continue." + + # Get public components from private key and calculate thumbprint + pubExponent64="$(printf '%x' "$(openssl rsa -in "${ACCOUNT_KEY}" -noout -text | awk '/publicExponent/ {print $2}')" | hex2bin | urlbase64)" + pubMod64="$(openssl rsa -in "${ACCOUNT_KEY}" -noout -modulus | cut -d'=' -f2 | hex2bin | urlbase64)" + + thumbprint="$(printf '{"e":"%s","kty":"RSA","n":"%s"}' "${pubExponent64}" "${pubMod64}" | openssl dgst -sha256 -binary | urlbase64)" + + # If we generated a new private key in the step above we have to register it with the acme-server + if [[ "${register_new_key}" = "yes" ]]; then + echo "+ Registering account key with letsencrypt..." + [[ ! -z "${CA_NEW_REG}" ]] || _exiterr "Certificate authority doesn't allow registrations." + # If an email for the contact has been provided then adding it to the registration request + FAILED=false + if [[ -n "${CONTACT_EMAIL}" ]]; then + (signed_request "${CA_NEW_REG}" '{"resource": "new-reg", "contact":["mailto:'"${CONTACT_EMAIL}"'"], "agreement": "'"$LICENSE"'"}' > "${ACCOUNT_KEY_JSON}") || FAILED=true + else + (signed_request "${CA_NEW_REG}" '{"resource": "new-reg", "agreement": "'"$LICENSE"'"}' > "${ACCOUNT_KEY_JSON}") || FAILED=true + fi + if [[ "${FAILED}" = "true" ]]; then + echo + echo + echo "Error registering account key. See message above for more information." + rm "${ACCOUNT_KEY}" "${ACCOUNT_KEY_JSON}" + exit 1 + fi + fi + +} + +# Different sed version for different os types... +_sed() { + if [[ "${OSTYPE}" = "Linux" ]]; then + sed -r "${@}" + else + sed -E "${@}" + fi +} + +# Print error message and exit with error +_exiterr() { + echo "ERROR: ${1}" >&2 + exit 1 +} + +# Remove newlines and whitespace from json +clean_json() { + tr -d '\r\n' | _sed -e 's/ +/ /g' -e 's/\{ /{/g' -e 's/ \}/}/g' -e 's/\[ /[/g' -e 's/ \]/]/g' +} + +# Encode data as url-safe formatted base64 +urlbase64() { + # urlbase64: base64 encoded string with '+' replaced with '-' and '/' replaced with '_' + openssl base64 -e | tr -d '\n\r' | _sed -e 's:=*$::g' -e 'y:+/:-_:' +} + +# Convert hex string to binary data +hex2bin() { + # Remove spaces, add leading zero, escape as hex string and parse with printf + printf -- "$(cat | _sed -e 's/[[:space:]]//g' -e 's/^(.(.{2})*)$/0\1/' -e 's/(.{2})/\\x\1/g')" +} + +# Get string value from json dictionary +get_json_string_value() { + local filter + filter=$(printf 's/.*"%s": *"\([^"]*\)".*/\\1/p' "$1") + sed -n "${filter}" +} + +# OpenSSL writes to stderr/stdout even when there are no errors. So just +# display the output if the exit code was != 0 to simplify debugging. +_openssl() { + set +e + out="$(openssl "${@}" 2>&1)" + res=$? + set -e + if [[ ${res} -ne 0 ]]; then + echo " + ERROR: failed to run $* (Exitcode: ${res})" >&2 + echo >&2 + echo "Details:" >&2 + echo "${out}" >&2 + echo >&2 + exit ${res} + fi +} + +# Send http(s) request with specified method +http_request() { + tempcont="$(_mktemp)" + + set +e + if [[ "${1}" = "head" ]]; then + statuscode="$(curl -s -w "%{http_code}" -o "${tempcont}" "${2}" -I)" + curlret="${?}" + elif [[ "${1}" = "get" ]]; then + statuscode="$(curl -s -w "%{http_code}" -o "${tempcont}" "${2}")" + curlret="${?}" + elif [[ "${1}" = "post" ]]; then + statuscode="$(curl -s -w "%{http_code}" -o "${tempcont}" "${2}" -d "${3}")" + curlret="${?}" + else + set -e + _exiterr "Unknown request method: ${1}" + fi + set -e + + if [[ ! "${curlret}" = "0" ]]; then + _exiterr "Problem connecting to server (${1} for ${2}; curl returned with ${curlret})" + fi + + if [[ ! "${statuscode:0:1}" = "2" ]]; then + echo " + ERROR: An error occurred while sending ${1}-request to ${2} (Status ${statuscode})" >&2 + echo >&2 + echo "Details:" >&2 + cat "${tempcont}" >&2 + rm -f "${tempcont}" + + # Wait for hook script to clean the challenge if used + if [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" != "yes" ]] && [[ -n "${challenge_token:+set}" ]]; then + "${HOOK}" "clean_challenge" '' "${challenge_token}" "${keyauth}" + fi + + # remove temporary domains.txt file if used + [[ -n "${PARAM_DOMAIN:-}" && -n "${DOMAINS_TXT:-}" ]] && rm "${DOMAINS_TXT}" + exit 1 + fi + + cat "${tempcont}" + rm -f "${tempcont}" +} + +# Send signed request +signed_request() { + # Encode payload as urlbase64 + payload64="$(printf '%s' "${2}" | urlbase64)" + + # Retrieve nonce from acme-server + nonce="$(http_request head "${CA}" | grep Replay-Nonce: | awk -F ': ' '{print $2}' | tr -d '\n\r')" + + # Build header with just our public key and algorithm information + header='{"alg": "RS256", "jwk": {"e": "'"${pubExponent64}"'", "kty": "RSA", "n": "'"${pubMod64}"'"}}' + + # Build another header which also contains the previously received nonce and encode it as urlbase64 + protected='{"alg": "RS256", "jwk": {"e": "'"${pubExponent64}"'", "kty": "RSA", "n": "'"${pubMod64}"'"}, "nonce": "'"${nonce}"'"}' + protected64="$(printf '%s' "${protected}" | urlbase64)" + + # Sign header with nonce and our payload with our private key and encode signature as urlbase64 + signed64="$(printf '%s' "${protected64}.${payload64}" | openssl dgst -sha256 -sign "${ACCOUNT_KEY}" | urlbase64)" + + # Send header + extended header + payload + signature to the acme-server + data='{"header": '"${header}"', "protected": "'"${protected64}"'", "payload": "'"${payload64}"'", "signature": "'"${signed64}"'"}' + + http_request post "${1}" "${data}" +} + +# Extracts all subject names from a CSR +# Outputs either the CN, or the SANs, one per line +extract_altnames() { + csr="${1}" # the CSR itself (not a file) + + if ! <<<"${csr}" openssl req -verify -noout 2>/dev/null; then + _exiterr "Certificate signing request isn't valid" + fi + + reqtext="$( <<<"${csr}" openssl req -noout -text )" + if <<<"${reqtext}" grep -q '^[[:space:]]*X509v3 Subject Alternative Name:[[:space:]]*$'; then + # SANs used, extract these + altnames="$( <<<"${reqtext}" grep -A1 '^[[:space:]]*X509v3 Subject Alternative Name:[[:space:]]*$' | tail -n1 )" + # split to one per line: + # shellcheck disable=SC1003 + altnames="$( <<<"${altnames}" _sed -e 's/^[[:space:]]*//; s/, /\'$'\n''/g' )" + # we can only get DNS: ones signed + if grep -qv '^DNS:' <<<"${altnames}"; then + _exiterr "Certificate signing request contains non-DNS Subject Alternative Names" + fi + # strip away the DNS: prefix + altnames="$( <<<"${altnames}" _sed -e 's/^DNS://' )" + echo "${altnames}" + + else + # No SANs, extract CN + altnames="$( <<<"${reqtext}" grep '^[[:space:]]*Subject:' | _sed -e 's/.* CN=([^ /,]*).*/\1/' )" + echo "${altnames}" + fi +} + +# Create certificate for domain(s) and outputs it FD 3 +sign_csr() { + csr="${1}" # the CSR itself (not a file) + + if { true >&3; } 2>/dev/null; then + : # fd 3 looks OK + else + _exiterr "sign_csr: FD 3 not open" + fi + + shift 1 || true + altnames="${*:-}" + if [ -z "${altnames}" ]; then + altnames="$( extract_altnames "${csr}" )" + fi + + if [[ -z "${CA_NEW_AUTHZ}" ]] || [[ -z "${CA_NEW_CERT}" ]]; then + _exiterr "Certificate authority doesn't allow certificate signing" + fi + + local idx=0 + if [[ -n "${ZSH_VERSION:-}" ]]; then + local -A challenge_uris challenge_tokens keyauths deploy_args + else + local -a challenge_uris challenge_tokens keyauths deploy_args + fi + + # Request challenges + for altname in ${altnames}; do + # Ask the acme-server for new challenge token and extract them from the resulting json block + echo " + Requesting challenge for ${altname}..." + response="$(signed_request "${CA_NEW_AUTHZ}" '{"resource": "new-authz", "identifier": {"type": "dns", "value": "'"${altname}"'"}}' | clean_json)" + + challenges="$(printf '%s\n' "${response}" | sed -n 's/.*\("challenges":[^\[]*\[[^]]*]\).*/\1/p')" + repl=$'\n''{' # fix syntax highlighting in Vim + challenge="$(printf "%s" "${challenges//\{/${repl}}" | grep \""${CHALLENGETYPE}"\")" + challenge_token="$(printf '%s' "${challenge}" | get_json_string_value token | _sed 's/[^A-Za-z0-9_\-]/_/g')" + challenge_uri="$(printf '%s' "${challenge}" | get_json_string_value uri)" + + if [[ -z "${challenge_token}" ]] || [[ -z "${challenge_uri}" ]]; then + _exiterr "Can't retrieve challenges (${response})" + fi + + # Challenge response consists of the challenge token and the thumbprint of our public certificate + keyauth="${challenge_token}.${thumbprint}" + + case "${CHALLENGETYPE}" in + "http-01") + # Store challenge response in well-known location and make world-readable (so that a webserver can access it) + printf '%s' "${keyauth}" > "${WELLKNOWN}/${challenge_token}" + chmod a+r "${WELLKNOWN}/${challenge_token}" + keyauth_hook="${keyauth}" + ;; + "dns-01") + # Generate DNS entry content for dns-01 validation + keyauth_hook="$(printf '%s' "${keyauth}" | openssl dgst -sha256 -binary | urlbase64)" + ;; + esac + + challenge_uris[${idx}]="${challenge_uri}" + keyauths[${idx}]="${keyauth}" + challenge_tokens[${idx}]="${challenge_token}" + # Note: assumes args will never have spaces! + deploy_args[${idx}]="${altname} ${challenge_token} ${keyauth_hook}" + idx=$((idx+1)) + done + + # Wait for hook script to deploy the challenges if used + # shellcheck disable=SC2068 + [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" = "yes" ]] && "${HOOK}" "deploy_challenge" ${deploy_args[@]} + + # Respond to challenges + idx=0 + for altname in ${altnames}; do + challenge_token="${challenge_tokens[${idx}]}" + keyauth="${keyauths[${idx}]}" + + # Wait for hook script to deploy the challenge if used + # shellcheck disable=SC2086 + [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" != "yes" ]] && "${HOOK}" "deploy_challenge" ${deploy_args[${idx}]} + + # Ask the acme-server to verify our challenge and wait until it is no longer pending + echo " + Responding to challenge for ${altname}..." + result="$(signed_request "${challenge_uris[${idx}]}" '{"resource": "challenge", "keyAuthorization": "'"${keyauth}"'"}' | clean_json)" + + reqstatus="$(printf '%s\n' "${result}" | get_json_string_value status)" + + while [[ "${reqstatus}" = "pending" ]]; do + sleep 1 + result="$(http_request get "${challenge_uris[${idx}]}")" + reqstatus="$(printf '%s\n' "${result}" | get_json_string_value status)" + done + + [[ "${CHALLENGETYPE}" = "http-01" ]] && rm -f "${WELLKNOWN}/${challenge_token}" + + # Wait for hook script to clean the challenge if used + if [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" != "yes" ]] && [[ -n "${challenge_token}" ]]; then + # shellcheck disable=SC2086 + "${HOOK}" "clean_challenge" ${deploy_args[${idx}]} + fi + idx=$((idx+1)) + + if [[ "${reqstatus}" = "valid" ]]; then + echo " + Challenge is valid!" + else + break + fi + done + + # Wait for hook script to clean the challenges if used + # shellcheck disable=SC2068 + [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" = "yes" ]] && "${HOOK}" "clean_challenge" ${deploy_args[@]} + + if [[ "${reqstatus}" != "valid" ]]; then + # Clean up any remaining challenge_tokens if we stopped early + if [[ "${CHALLENGETYPE}" = "http-01" ]]; then + while [ ${idx} -lt ${#challenge_tokens[@]} ]; do + rm -f "${WELLKNOWN}/${challenge_tokens[${idx}]}" + idx=$((idx+1)) + done + fi + + _exiterr "Challenge is invalid! (returned: ${reqstatus}) (result: ${result})" + fi + + # Finally request certificate from the acme-server and store it in cert-${timestamp}.pem and link from cert.pem + echo " + Requesting certificate..." + csr64="$( <<<"${csr}" openssl req -outform DER | urlbase64)" + crt64="$(signed_request "${CA_NEW_CERT}" '{"resource": "new-cert", "csr": "'"${csr64}"'"}' | openssl base64 -e)" + crt="$( printf -- '-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----\n' "${crt64}" )" + + # Try to load the certificate to detect corruption + echo " + Checking certificate..." + _openssl x509 -text <<<"${crt}" + + echo "${crt}" >&3 + + unset challenge_token + echo " + Done!" +} + +# Create certificate for domain(s) +sign_domain() { + domain="${1}" + altnames="${*}" + timestamp="$(date +%s)" + + echo " + Signing domains..." + if [[ -z "${CA_NEW_AUTHZ}" ]] || [[ -z "${CA_NEW_CERT}" ]]; then + _exiterr "Certificate authority doesn't allow certificate signing" + fi + + # If there is no existing certificate directory => make it + if [[ ! -e "${CERTDIR}/${domain}" ]]; then + echo " + Creating new directory ${CERTDIR}/${domain} ..." + mkdir -p "${CERTDIR}/${domain}" || _exiterr "Unable to create directory ${CERTDIR}/${domain}" + fi + + privkey="privkey.pem" + # generate a new private key if we need or want one + if [[ ! -r "${CERTDIR}/${domain}/privkey.pem" ]] || [[ "${PRIVATE_KEY_RENEW}" = "yes" ]]; then + echo " + Generating private key..." + privkey="privkey-${timestamp}.pem" + case "${KEY_ALGO}" in + rsa) _openssl genrsa -out "${CERTDIR}/${domain}/privkey-${timestamp}.pem" "${KEYSIZE}";; + prime256v1|secp384r1) _openssl ecparam -genkey -name "${KEY_ALGO}" -out "${CERTDIR}/${domain}/privkey-${timestamp}.pem";; + esac + fi + + # Generate signing request config and the actual signing request + echo " + Generating signing request..." + SAN="" + for altname in ${altnames}; do + SAN+="DNS:${altname}, " + done + SAN="${SAN%%, }" + local tmp_openssl_cnf + tmp_openssl_cnf="$(_mktemp)" + cat "${OPENSSL_CNF}" > "${tmp_openssl_cnf}" + printf "[SAN]\nsubjectAltName=%s" "${SAN}" >> "${tmp_openssl_cnf}" + if [ "${OCSP_MUST_STAPLE}" = "yes" ]; then + printf "\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >> "${tmp_openssl_cnf}" + fi + openssl req -new -sha256 -key "${CERTDIR}/${domain}/${privkey}" -out "${CERTDIR}/${domain}/cert-${timestamp}.csr" -subj "/CN=${domain}/" -reqexts SAN -config "${tmp_openssl_cnf}" + rm -f "${tmp_openssl_cnf}" + + crt_path="${CERTDIR}/${domain}/cert-${timestamp}.pem" + # shellcheck disable=SC2086 + sign_csr "$(< "${CERTDIR}/${domain}/cert-${timestamp}.csr" )" ${altnames} 3>"${crt_path}" + + # Create fullchain.pem + echo " + Creating fullchain.pem..." + cat "${crt_path}" > "${CERTDIR}/${domain}/fullchain-${timestamp}.pem" + http_request get "$(openssl x509 -in "${CERTDIR}/${domain}/cert-${timestamp}.pem" -noout -text | grep 'CA Issuers - URI:' | cut -d':' -f2-)" > "${CERTDIR}/${domain}/chain-${timestamp}.pem" + if ! grep -q "BEGIN CERTIFICATE" "${CERTDIR}/${domain}/chain-${timestamp}.pem"; then + openssl x509 -in "${CERTDIR}/${domain}/chain-${timestamp}.pem" -inform DER -out "${CERTDIR}/${domain}/chain-${timestamp}.pem" -outform PEM + fi + cat "${CERTDIR}/${domain}/chain-${timestamp}.pem" >> "${CERTDIR}/${domain}/fullchain-${timestamp}.pem" + + # Update symlinks + [[ "${privkey}" = "privkey.pem" ]] || ln -sf "privkey-${timestamp}.pem" "${CERTDIR}/${domain}/privkey.pem" + + ln -sf "chain-${timestamp}.pem" "${CERTDIR}/${domain}/chain.pem" + ln -sf "fullchain-${timestamp}.pem" "${CERTDIR}/${domain}/fullchain.pem" + ln -sf "cert-${timestamp}.csr" "${CERTDIR}/${domain}/cert.csr" + ln -sf "cert-${timestamp}.pem" "${CERTDIR}/${domain}/cert.pem" + + # Wait for hook script to clean the challenge and to deploy cert if used + export KEY_ALGO + [[ -n "${HOOK}" ]] && "${HOOK}" "deploy_cert" "${domain}" "${CERTDIR}/${domain}/privkey.pem" "${CERTDIR}/${domain}/cert.pem" "${CERTDIR}/${domain}/fullchain.pem" "${CERTDIR}/${domain}/chain.pem" "${timestamp}" + + unset challenge_token + echo " + Done!" +} + +# Usage: --cron (-c) +# Description: Sign/renew non-existant/changed/expiring certificates. +command_sign_domains() { + init_system + + if [[ -n "${PARAM_DOMAIN:-}" ]]; then + DOMAINS_TXT="$(_mktemp)" + printf -- "${PARAM_DOMAIN}" > "${DOMAINS_TXT}" + elif [[ -e "${DOMAINS_TXT}" ]]; then + if [[ ! -r "${DOMAINS_TXT}" ]]; then + _exiterr "domains.txt found but not readable" + fi + else + _exiterr "domains.txt not found and --domain not given" + fi + + # Generate certificates for all domains found in domains.txt. Check if existing certificate are about to expire + ORIGIFS="${IFS}" + IFS=$'\n' + for line in $(<"${DOMAINS_TXT}" tr -d '\r' | tr '[:upper:]' '[:lower:]' | _sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g' -e 's/[[:space:]]+/ /g' | (grep -vE '^(#|$)' || true)); do + reset_configvars + IFS="${ORIGIFS}" + domain="$(printf '%s\n' "${line}" | cut -d' ' -f1)" + morenames="$(printf '%s\n' "${line}" | cut -s -d' ' -f2-)" + cert="${CERTDIR}/${domain}/cert.pem" + + force_renew="${PARAM_FORCE:-no}" + + if [[ -z "${morenames}" ]];then + echo "Processing ${domain}" + else + echo "Processing ${domain} with alternative names: ${morenames}" + fi + + # read cert config + # for now this loads the certificate specific config in a subshell and parses a diff of set variables. + # we could just source the config file but i decided to go this way to protect people from accidentally overriding + # variables used internally by this script itself. + if [ -f "${CERTDIR}/${domain}/config" ]; then + echo " + Using certificate specific config file!" + ORIGIFS="${IFS}" + IFS=$'\n' + for cfgline in $( + beforevars="$(_mktemp)" + aftervars="$(_mktemp)" + set > "${beforevars}" + # shellcheck disable=SC1090 + . "${CERTDIR}/${domain}/config" + set > "${aftervars}" + diff -u "${beforevars}" "${aftervars}" | grep -E '^\+[^+]' + rm "${beforevars}" + rm "${aftervars}" + ); do + config_var="$(echo "${cfgline:1}" | cut -d'=' -f1)" + config_value="$(echo "${cfgline:1}" | cut -d'=' -f2-)" + case "${config_var}" in + KEY_ALGO|OCSP_MUST_STAPLE|PRIVATE_KEY_RENEW|KEYSIZE|CHALLENGETYPE|HOOK|WELLKNOWN|HOOK_CHAIN|OPENSSL_CNF|RENEW_DAYS) + echo " + ${config_var} = ${config_value}" + declare -- "${config_var}=${config_value}" + ;; + _) ;; + *) echo " ! Setting ${config_var} on a per-certificate base is not (yet) supported" + esac + done + IFS="${ORIGIFS}" + fi + verify_config + + if [[ -e "${cert}" ]]; then + printf " + Checking domain name(s) of existing cert..." + + certnames="$(openssl x509 -in "${cert}" -text -noout | grep DNS: | _sed 's/DNS://g' | tr -d ' ' | tr ',' '\n' | sort -u | tr '\n' ' ' | _sed 's/ $//')" + givennames="$(echo "${domain}" "${morenames}"| tr ' ' '\n' | sort -u | tr '\n' ' ' | _sed 's/ $//' | _sed 's/^ //')" + + if [[ "${certnames}" = "${givennames}" ]]; then + echo " unchanged." + else + echo " changed!" + echo " + Domain name(s) are not matching!" + echo " + Names in old certificate: ${certnames}" + echo " + Configured names: ${givennames}" + echo " + Forcing renew." + force_renew="yes" + fi + fi + + if [[ -e "${cert}" ]]; then + echo " + Checking expire date of existing cert..." + valid="$(openssl x509 -enddate -noout -in "${cert}" | cut -d= -f2- )" + + printf " + Valid till %s " "${valid}" + if openssl x509 -checkend $((RENEW_DAYS * 86400)) -noout -in "${cert}"; then + printf "(Longer than %d days). " "${RENEW_DAYS}" + if [[ "${force_renew}" = "yes" ]]; then + echo "Ignoring because renew was forced!" + else + # Certificate-Names unchanged and cert is still valid + echo "Skipping renew!" + [[ -n "${HOOK}" ]] && "${HOOK}" "unchanged_cert" "${domain}" "${CERTDIR}/${domain}/privkey.pem" "${CERTDIR}/${domain}/cert.pem" "${CERTDIR}/${domain}/fullchain.pem" "${CERTDIR}/${domain}/chain.pem" + continue + fi + else + echo "(Less than ${RENEW_DAYS} days). Renewing!" + fi + fi + + # shellcheck disable=SC2086 + sign_domain ${line} + done + + # remove temporary domains.txt file if used + [[ -n "${PARAM_DOMAIN:-}" ]] && rm -f "${DOMAINS_TXT}" + + exit 0 +} + +# Usage: --signcsr (-s) path/to/csr.pem +# Description: Sign a given CSR, output CRT on stdout (advanced usage) +command_sign_csr() { + # redirect stdout to stderr + # leave stdout over at fd 3 to output the cert + exec 3>&1 1>&2 + + init_system + + csrfile="${1}" + if [ ! -r "${csrfile}" ]; then + _exiterr "Could not read certificate signing request ${csrfile}" + fi + + # gen cert + certfile="$(_mktemp)" + sign_csr "$(< "${csrfile}" )" 3> "${certfile}" + + # get and convert ca cert + chainfile="$(_mktemp)" + http_request get "$(openssl x509 -in "${certfile}" -noout -text | grep 'CA Issuers - URI:' | cut -d':' -f2-)" > "${chainfile}" + + if ! grep -q "BEGIN CERTIFICATE" "${chainfile}"; then + openssl x509 -inform DER -in "${chainfile}" -outform PEM -out "${chainfile}" + fi + + # output full chain + echo "# CERT #" >&3 + cat "${certfile}" >&3 + echo >&3 + echo "# CHAIN #" >&3 + cat "${chainfile}" >&3 + + # cleanup + rm "${certfile}" + rm "${chainfile}" + + exit 0 +} + +# Usage: --revoke (-r) path/to/cert.pem +# Description: Revoke specified certificate +command_revoke() { + init_system + + [[ -n "${CA_REVOKE_CERT}" ]] || _exiterr "Certificate authority doesn't allow certificate revocation." + + cert="${1}" + if [[ -L "${cert}" ]]; then + # follow symlink and use real certificate name (so we move the real file and not the symlink at the end) + local link_target + link_target="$(readlink -n "${cert}")" + if [[ "${link_target}" =~ ^/ ]]; then + cert="${link_target}" + else + cert="$(dirname "${cert}")/${link_target}" + fi + fi + [[ -f "${cert}" ]] || _exiterr "Could not find certificate ${cert}" + + echo "Revoking ${cert}" + + cert64="$(openssl x509 -in "${cert}" -inform PEM -outform DER | urlbase64)" + response="$(signed_request "${CA_REVOKE_CERT}" '{"resource": "revoke-cert", "certificate": "'"${cert64}"'"}' | clean_json)" + # if there is a problem with our revoke request _request (via signed_request) will report this and "exit 1" out + # so if we are here, it is safe to assume the request was successful + echo " + Done." + echo " + Renaming certificate to ${cert}-revoked" + mv -f "${cert}" "${cert}-revoked" +} + +# Usage: --cleanup (-gc) +# Description: Move unused certificate files to archive directory +command_cleanup() { + load_config + + # Create global archive directory if not existant + if [[ ! -e "${BASEDIR}/archive" ]]; then + mkdir "${BASEDIR}/archive" + fi + + # Loop over all certificate directories + for certdir in "${CERTDIR}/"*; do + # Skip if entry is not a folder + [[ -d "${certdir}" ]] || continue + + # Get certificate name + certname="$(basename "${certdir}")" + + # Create certitifaces archive directory if not existant + archivedir="${BASEDIR}/archive/${certname}" + if [[ ! -e "${archivedir}" ]]; then + mkdir "${archivedir}" + fi + + # Loop over file-types (certificates, keys, signing-requests, ...) + for filetype in cert.csr cert.pem chain.pem fullchain.pem privkey.pem; do + # Skip if symlink is broken + [[ -r "${certdir}/${filetype}" ]] || continue + + # Look up current file in use + current="$(basename "$(readlink "${certdir}/${filetype}")")" + + # Split filetype into name and extension + filebase="$(echo "${filetype}" | cut -d. -f1)" + fileext="$(echo "${filetype}" | cut -d. -f2)" + + # Loop over all files of this type + for file in "${certdir}/${filebase}-"*".${fileext}"; do + # Handle case where no files match the wildcard + [[ -f "${file}" ]] || break + + # Check if current file is in use, if unused move to archive directory + filename="$(basename "${file}")" + if [[ ! "${filename}" = "${current}" ]]; then + echo "Moving unused file to archive directory: ${certname}/${filename}" + mv "${certdir}/${filename}" "${archivedir}/${filename}" + fi + done + done + done + + exit 0 +} + +# Usage: --help (-h) +# Description: Show help text +command_help() { + printf "Usage: %s [-h] [command [argument]] [parameter [argument]] [parameter [argument]] ...\n\n" "${0}" + printf "Default command: help\n\n" + echo "Commands:" + grep -e '^[[:space:]]*# Usage:' -e '^[[:space:]]*# Description:' -e '^command_.*()[[:space:]]*{' "${0}" | while read -r usage; read -r description; read -r command; do + if [[ ! "${usage}" =~ Usage ]] || [[ ! "${description}" =~ Description ]] || [[ ! "${command}" =~ ^command_ ]]; then + _exiterr "Error generating help text." + fi + printf " %-32s %s\n" "${usage##"# Usage: "}" "${description##"# Description: "}" + done + printf -- "\nParameters:\n" + grep -E -e '^[[:space:]]*# PARAM_Usage:' -e '^[[:space:]]*# PARAM_Description:' "${0}" | while read -r usage; read -r description; do + if [[ ! "${usage}" =~ Usage ]] || [[ ! "${description}" =~ Description ]]; then + _exiterr "Error generating help text." + fi + printf " %-32s %s\n" "${usage##"# PARAM_Usage: "}" "${description##"# PARAM_Description: "}" + done +} + +# Usage: --env (-e) +# Description: Output configuration variables for use in other scripts +command_env() { + echo "# letsencrypt.sh configuration" + load_config + typeset -p CA LICENSE CERTDIR CHALLENGETYPE DOMAINS_TXT HOOK HOOK_CHAIN RENEW_DAYS ACCOUNT_KEY ACCOUNT_KEY_JSON KEYSIZE WELLKNOWN PRIVATE_KEY_RENEW OPENSSL_CNF CONTACT_EMAIL LOCKFILE +} + +# Main method (parses script arguments and calls command_* methods) +main() { + COMMAND="" + set_command() { + [[ -z "${COMMAND}" ]] || _exiterr "Only one command can be executed at a time. See help (-h) for more information." + COMMAND="${1}" + } + + check_parameters() { + if [[ -z "${1:-}" ]]; then + echo "The specified command requires additional parameters. See help:" >&2 + echo >&2 + command_help >&2 + exit 1 + elif [[ "${1:0:1}" = "-" ]]; then + _exiterr "Invalid argument: ${1}" + fi + } + + [[ -z "${@}" ]] && eval set -- "--help" + + while (( ${#} )); do + case "${1}" in + --help|-h) + command_help + exit 0 + ;; + + --env|-e) + set_command env + ;; + + --cron|-c) + set_command sign_domains + ;; + + --signcsr|-s) + shift 1 + set_command sign_csr + check_parameters "${1:-}" + PARAM_CSR="${1}" + ;; + + --revoke|-r) + shift 1 + set_command revoke + check_parameters "${1:-}" + PARAM_REVOKECERT="${1}" + ;; + + --cleanup|-gc) + set_command cleanup + ;; + + # PARAM_Usage: --domain (-d) domain.tld + # PARAM_Description: Use specified domain name(s) instead of domains.txt entry (one certificate!) + --domain|-d) + shift 1 + check_parameters "${1:-}" + if [[ -z "${PARAM_DOMAIN:-}" ]]; then + PARAM_DOMAIN="${1}" + else + PARAM_DOMAIN="${PARAM_DOMAIN} ${1}" + fi + ;; + + + # PARAM_Usage: --force (-x) + # PARAM_Description: Force renew of certificate even if it is longer valid than value in RENEW_DAYS + --force|-x) + PARAM_FORCE="yes" + ;; + + # PARAM_Usage: --ocsp + # PARAM_Description: Sets option in CSR indicating OCSP stapling to be mandatory + --ocsp) + PARAM_OCSP_MUST_STAPLE="yes" + ;; + + # PARAM_Usage: --privkey (-p) path/to/key.pem + # PARAM_Description: Use specified private key instead of account key (useful for revocation) + --privkey|-p) + shift 1 + check_parameters "${1:-}" + PARAM_ACCOUNT_KEY="${1}" + ;; + + # PARAM_Usage: --config (-f) path/to/config + # PARAM_Description: Use specified config file + --config|-f) + shift 1 + check_parameters "${1:-}" + CONFIG="${1}" + ;; + + # PARAM_Usage: --hook (-k) path/to/hook.sh + # PARAM_Description: Use specified script for hooks + --hook|-k) + shift 1 + check_parameters "${1:-}" + PARAM_HOOK="${1}" + ;; + + # PARAM_Usage: --out (-o) certs/directory + # PARAM_Description: Output certificates into the specified directory + --out|-o) + shift 1 + check_parameters "${1:-}" + PARAM_CERTDIR="${1}" + ;; + + # PARAM_Usage: --challenge (-t) http-01|dns-01 + # PARAM_Description: Which challenge should be used? Currently http-01 and dns-01 are supported + --challenge|-t) + shift 1 + check_parameters "${1:-}" + PARAM_CHALLENGETYPE="${1}" + ;; + + # PARAM_Usage: --algo (-a) rsa|prime256v1|secp384r1 + # PARAM_Description: Which public key algorithm should be used? Supported: rsa, prime256v1 and secp384r1 + --algo|-a) + shift 1 + check_parameters "${1:-}" + PARAM_KEY_ALGO="${1}" + ;; + + *) + echo "Unknown parameter detected: ${1}" >&2 + echo >&2 + command_help >&2 + exit 1 + ;; + esac + + shift 1 + done + + case "${COMMAND}" in + env) command_env;; + sign_domains) command_sign_domains;; + sign_csr) command_sign_csr "${PARAM_CSR}";; + revoke) command_revoke "${PARAM_REVOKECERT}";; + cleanup) command_cleanup;; + *) command_help; exit 1;; + esac +} + +# Determine OS type +OSTYPE="$(uname)" + +# Check for missing dependencies +check_dependencies + +# Run script +main "${@:-}" diff --git a/dist/cert.hook.d.ts b/dist/cert.hook.d.ts index e69de29..62d7805 100644 --- a/dist/cert.hook.d.ts +++ b/dist/cert.hook.d.ts @@ -0,0 +1 @@ +import "typings-global"; diff --git a/dist/cert.hook.js b/dist/cert.hook.js old mode 100644 new mode 100755 index 7614985..627407f --- a/dist/cert.hook.js +++ b/dist/cert.hook.js @@ -1,3 +1,51 @@ +#!/usr/bin/env node "use strict"; +require("typings-global"); +var plugins = require("./cert.plugins"); +var paths = require("./cert.paths"); +var smartcli = new plugins.smartcli.Smartcli(); +var config = plugins.smartfile.local.toObjectSync(paths.config); +var cflare = new plugins.cflare.CflareAccount(); +cflare.auth({ + email: config.cfEmail, + key: config.cfKey +}); +var setChallenge = function (domainNameArg, challengeArg) { + var done = plugins.q.defer(); + cflare.createRecord(prefixName(domainNameArg), "TXT", challengeArg).then(function () { + cooldown().then(function () { + done.resolve(); + }); + }); + return done.promise; +}; +var cleanChallenge = function (domainNameArg) { + var done = plugins.q.defer(); + cflare.removeRecord(prefixName(domainNameArg), "TXT"); + return done.promise; +}; +var cooldown = function () { + var done = plugins.q.defer(); + console.log("Cooling down!"); + setTimeout(function () { + done.resolve(); + }, 20000); + return done.promise; +}; +var prefixName = function (domainNameArg) { + return "_acme-challenge." + domainNameArg; +}; +smartcli.addCommand({ + commandName: "deploy_challenge" +}).then(function (argv) { + console.log(argv); + setChallenge(argv._[1], argv._[3]); +}); +smartcli.addCommand({ + commandName: "clean_challenge" +}).then(function (argv) { + cleanChallenge(argv._[1]); +}); +smartcli.startParse(); -//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsImZpbGUiOiJjZXJ0Lmhvb2suanMiLCJzb3VyY2VzQ29udGVudCI6W119 +//# sourceMappingURL=data:application/json;charset=utf8;base64,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cmNlc0NvbnRlbnQiOlsiIyEvdXNyL2Jpbi9lbnYgbm9kZVxuLy8gdGhlIHNoZWJhbmcgbGluZSBhYm92ZSBtYWtlcyBzdXJlIHRoaXMgc2NyaXB0IHdpbGwgZ2V0IGludGVycHJldGVkIGJ5IG5vZGVcblxuaW1wb3J0IFwidHlwaW5ncy1nbG9iYWxcIjtcbmltcG9ydCAqIGFzIHBsdWdpbnMgZnJvbSBcIi4vY2VydC5wbHVnaW5zXCI7XG5pbXBvcnQgKiBhcyBwYXRocyBmcm9tIFwiLi9jZXJ0LnBhdGhzXCI7XG5cbmxldCBzbWFydGNsaSA9IG5ldyBwbHVnaW5zLnNtYXJ0Y2xpLlNtYXJ0Y2xpKCk7XG5cbmxldCBjb25maWcgPSBwbHVnaW5zLnNtYXJ0ZmlsZS5sb2NhbC50b09iamVjdFN5bmMocGF0aHMuY29uZmlnKTtcbmxldCBjZmxhcmUgPSBuZXcgcGx1Z2lucy5jZmxhcmUuQ2ZsYXJlQWNjb3VudCgpO1xuY2ZsYXJlLmF1dGgoe1xuICAgIGVtYWlsOiBjb25maWcuY2ZFbWFpbCxcbiAgICBrZXk6IGNvbmZpZy5jZktleVxufSk7XG5cbmxldCBzZXRDaGFsbGVuZ2UgPSAoZG9tYWluTmFtZUFyZzogc3RyaW5nLCBjaGFsbGVuZ2VBcmc6IHN0cmluZykgPT4ge1xuICAgIGxldCBkb25lID0gcGx1Z2lucy5xLmRlZmVyKCk7XG4gICAgY2ZsYXJlLmNyZWF0ZVJlY29yZChwcmVmaXhOYW1lKGRvbWFpbk5hbWVBcmcpLCBcIlRYVFwiLCBjaGFsbGVuZ2VBcmcpLnRoZW4oKCkgPT4ge1xuICAgICAgICBjb29sZG93bigpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgZG9uZS5yZXNvbHZlKCk7XG4gICAgICAgIH0pO1xuICAgIH0pO1xuICAgIHJldHVybiBkb25lLnByb21pc2U7XG59XG5cbmxldCBjbGVhbkNoYWxsZW5nZSA9IChkb21haW5OYW1lQXJnKSA9PiB7XG4gICAgbGV0IGRvbmUgPSBwbHVnaW5zLnEuZGVmZXIoKTtcbiAgICBjZmxhcmUucmVtb3ZlUmVjb3JkKHByZWZpeE5hbWUoZG9tYWluTmFtZUFyZyksIFwiVFhUXCIpO1xuICAgIHJldHVybiBkb25lLnByb21pc2U7XG59XG5cbmxldCBjb29sZG93biA9ICgpID0+IHtcbiAgICBsZXQgZG9uZSA9IHBsdWdpbnMucS5kZWZlcigpO1xuICAgIGNvbnNvbGUubG9nKFwiQ29vbGluZyBkb3duIVwiKTtcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgZG9uZS5yZXNvbHZlKCk7XG4gICAgfSwgMjAwMDApXG4gICAgcmV0dXJuIGRvbmUucHJvbWlzZTtcbn1cblxubGV0IHByZWZpeE5hbWUgPSAoZG9tYWluTmFtZUFyZzogc3RyaW5nKTogc3RyaW5nID0+IHtcbiAgICByZXR1cm4gXCJfYWNtZS1jaGFsbGVuZ2UuXCIgKyBkb21haW5OYW1lQXJnO1xufVxuXG5zbWFydGNsaS5hZGRDb21tYW5kKHtcbiAgICBjb21tYW5kTmFtZTogXCJkZXBsb3lfY2hhbGxlbmdlXCJcbn0pLnRoZW4oKGFyZ3YpID0+IHtcbiAgICBjb25zb2xlLmxvZyhhcmd2KVxuICAgIHNldENoYWxsZW5nZShhcmd2Ll9bMV0sIGFyZ3YuX1szXSk7XG59KTtcblxuc21hcnRjbGkuYWRkQ29tbWFuZCh7XG4gICAgY29tbWFuZE5hbWU6IFwiY2xlYW5fY2hhbGxlbmdlXCJcbn0pLnRoZW4oKGFyZ3YpID0+IHtcbiAgICBjbGVhbkNoYWxsZW5nZShhcmd2Ll9bMV0pO1xufSk7XG5cbnNtYXJ0Y2xpLnN0YXJ0UGFyc2UoKTtcbiJdfQ== diff --git a/dist/cert.paths.d.ts b/dist/cert.paths.d.ts index ef561cc..74fab5a 100644 --- a/dist/cert.paths.d.ts +++ b/dist/cert.paths.d.ts @@ -1,2 +1,5 @@ import "typings-global"; -export import path = require("path"); +export declare let certHook: string; +export declare let config: string; +export declare let letsencryptSh: string; +export declare let sslDir: string; diff --git a/dist/cert.paths.js b/dist/cert.paths.js index 88e630c..f7f33ee 100644 --- a/dist/cert.paths.js +++ b/dist/cert.paths.js @@ -1,5 +1,9 @@ "use strict"; require("typings-global"); -exports.path = require("path"); +var plugins = require("./cert.plugins"); +exports.certHook = plugins.path.join(__dirname, "cert.hook.js"); +exports.config = plugins.path.join(__dirname, "assets/config.json"); +exports.letsencryptSh = plugins.path.join(__dirname, "assets/letsencrypt.sh"); +exports.sslDir = plugins.path.join(__dirname, "/assets/certs"); -//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImNlcnQucGF0aHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLFFBQU8sZ0JBQWdCLENBQUMsQ0FBQTtBQUNWLFlBQUksV0FBVyxNQUFNLENBQUMsQ0FBQyIsImZpbGUiOiJjZXJ0LnBhdGhzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFwidHlwaW5ncy1nbG9iYWxcIjtcbmV4cG9ydCBpbXBvcnQgcGF0aCA9IHJlcXVpcmUoXCJwYXRoXCIpO1xuXG4iXX0= +//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImNlcnQucGF0aHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLFFBQU8sZ0JBQWdCLENBQUMsQ0FBQTtBQUN4QixJQUFZLE9BQU8sV0FBTSxnQkFBZ0IsQ0FBQyxDQUFBO0FBRS9CLGdCQUFRLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFDLGNBQWMsQ0FBQyxDQUFDO0FBQ3ZELGNBQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUMsb0JBQW9CLENBQUMsQ0FBQztBQUMzRCxxQkFBYSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBQyx1QkFBdUIsQ0FBQyxDQUFDO0FBQ3JFLGNBQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUMsZUFBZSxDQUFDLENBQUMiLCJmaWxlIjoiY2VydC5wYXRocy5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBcInR5cGluZ3MtZ2xvYmFsXCI7XG5pbXBvcnQgKiBhcyBwbHVnaW5zIGZyb20gXCIuL2NlcnQucGx1Z2luc1wiO1xuXG5leHBvcnQgbGV0IGNlcnRIb29rID0gcGx1Z2lucy5wYXRoLmpvaW4oX19kaXJuYW1lLFwiY2VydC5ob29rLmpzXCIpO1xuZXhwb3J0IGxldCBjb25maWcgPSBwbHVnaW5zLnBhdGguam9pbihfX2Rpcm5hbWUsXCJhc3NldHMvY29uZmlnLmpzb25cIik7XG5leHBvcnQgbGV0IGxldHNlbmNyeXB0U2ggPSBwbHVnaW5zLnBhdGguam9pbihfX2Rpcm5hbWUsXCJhc3NldHMvbGV0c2VuY3J5cHQuc2hcIik7XG5leHBvcnQgbGV0IHNzbERpciA9IHBsdWdpbnMucGF0aC5qb2luKF9fZGlybmFtZSxcIi9hc3NldHMvY2VydHNcIik7Il19 diff --git a/dist/cert.plugins.d.ts b/dist/cert.plugins.d.ts index e69de29..0281066 100644 --- a/dist/cert.plugins.d.ts +++ b/dist/cert.plugins.d.ts @@ -0,0 +1,10 @@ +import "typings-global"; +export import beautylog = require("beautylog"); +export import cflare = require("cflare"); +export declare let fs: any; +export import path = require("path"); +export declare let q: any; +export declare let shelljs: any; +export import smartcli = require("smartcli"); +export import smartfile = require("smartfile"); +export import smartstring = require("smartstring"); diff --git a/dist/cert.plugins.js b/dist/cert.plugins.js index 0de51f5..9134de3 100644 --- a/dist/cert.plugins.js +++ b/dist/cert.plugins.js @@ -1,3 +1,13 @@ +"use strict"; +require("typings-global"); +exports.beautylog = require("beautylog"); +exports.cflare = require("cflare"); +exports.fs = require("fs-extra"); +exports.path = require("path"); +exports.q = require("q"); +exports.shelljs = require("shelljs"); +exports.smartcli = require("smartcli"); +exports.smartfile = require("smartfile"); +exports.smartstring = require("smartstring"); - -//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsImZpbGUiOiJjZXJ0LnBsdWdpbnMuanMiLCJzb3VyY2VzQ29udGVudCI6W119 +//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImNlcnQucGx1Z2lucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsUUFBTyxnQkFBZ0IsQ0FBQyxDQUFBO0FBQ1YsaUJBQVMsV0FBVyxXQUFXLENBQUMsQ0FBQztBQUNqQyxjQUFNLFdBQVcsUUFBUSxDQUFDLENBQUM7QUFDOUIsVUFBRSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztBQUN0QixZQUFJLFdBQVcsTUFBTSxDQUFDLENBQUM7QUFDMUIsU0FBQyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUNqQixlQUFPLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBQzFCLGdCQUFRLFdBQVcsVUFBVSxDQUFDLENBQUM7QUFDL0IsaUJBQVMsV0FBVyxXQUFXLENBQUMsQ0FBQztBQUNqQyxtQkFBVyxXQUFXLGFBQWEsQ0FBQyxDQUFDIiwiZmlsZSI6ImNlcnQucGx1Z2lucy5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBcInR5cGluZ3MtZ2xvYmFsXCI7XG5leHBvcnQgaW1wb3J0IGJlYXV0eWxvZyA9IHJlcXVpcmUoXCJiZWF1dHlsb2dcIik7XG5leHBvcnQgaW1wb3J0IGNmbGFyZSA9IHJlcXVpcmUoXCJjZmxhcmVcIik7XG5leHBvcnQgbGV0IGZzID0gcmVxdWlyZShcImZzLWV4dHJhXCIpO1xuZXhwb3J0IGltcG9ydCBwYXRoID0gcmVxdWlyZShcInBhdGhcIik7XG5leHBvcnQgbGV0IHEgPSByZXF1aXJlKFwicVwiKTtcbmV4cG9ydCBsZXQgc2hlbGxqcyA9IHJlcXVpcmUoXCJzaGVsbGpzXCIpO1xuZXhwb3J0IGltcG9ydCBzbWFydGNsaSA9IHJlcXVpcmUoXCJzbWFydGNsaVwiKTtcbmV4cG9ydCBpbXBvcnQgc21hcnRmaWxlID0gcmVxdWlyZShcInNtYXJ0ZmlsZVwiKTtcbmV4cG9ydCBpbXBvcnQgc21hcnRzdHJpbmcgPSByZXF1aXJlKFwic21hcnRzdHJpbmdcIik7XG5cbiJdfQ== diff --git a/dist/index.d.ts b/dist/index.d.ts index 7854aba..69de404 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -11,7 +11,7 @@ export declare class Cert { sslDir: string; gitOriginRepo?: string; }); - getDomainCert(): void; + getDomainCert(domainNameArg: string): any; } export declare class Certificate { domainName: string; diff --git a/dist/index.js b/dist/index.js index 92f2bf2..4fdba3b 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,13 +1,26 @@ "use strict"; +var plugins = require("./cert.plugins"); +var paths = require("./cert.paths"); var Cert = (function () { function Cert(optionsArg) { this.cfEmail = optionsArg.cfEmail; this.cfKey = optionsArg.cfKey; this.sslDir = optionsArg.sslDir; this.gitOriginRepo = optionsArg.gitOriginRepo; + var config = { + cfEmail: this.cfEmail, + cfKey: this.cfKey + }; + plugins.smartfile.memory.toFsSync(JSON.stringify(config), { fileName: "config.json", filePath: plugins.path.join(__dirname, "assets/") }); } ; - Cert.prototype.getDomainCert = function () { }; + Cert.prototype.getDomainCert = function (domainNameArg) { + var done = plugins.q.defer(); + plugins.shelljs.exec("chmod 700 " + paths.letsencryptSh); + plugins.shelljs.exec("chmod 700 " + paths.certHook); + plugins.shelljs.exec("bash -c \"" + paths.letsencryptSh + " -c -d " + domainNameArg + " -t dns-01 -k " + paths.certHook + " -o " + paths.sslDir + "\""); + return done.promise; + }; ; return Cert; }()); @@ -20,4 +33,4 @@ var Certificate = (function () { }()); exports.Certificate = Certificate; -//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFFQTtJQU9JLGNBQVksVUFLWDtRQUNHLElBQUksQ0FBQyxPQUFPLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQztRQUNsQyxJQUFJLENBQUMsS0FBSyxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUM7UUFDOUIsSUFBSSxDQUFDLE1BQU0sR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDO1FBQ2hDLElBQUksQ0FBQyxhQUFhLEdBQUcsVUFBVSxDQUFDLGFBQWEsQ0FBQztJQUNsRCxDQUFDOztJQUNELDRCQUFhLEdBQWIsY0FBZ0IsQ0FBQzs7SUFDckIsV0FBQztBQUFELENBbkJBLEFBbUJDLElBQUE7QUFuQlksWUFBSSxPQW1CaEIsQ0FBQTtBQUVEO0lBSUk7SUFFQSxDQUFDOztJQUNMLGtCQUFDO0FBQUQsQ0FQQSxBQU9DLElBQUE7QUFQWSxtQkFBVyxjQU92QixDQUFBIiwiZmlsZSI6ImluZGV4LmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgcGF0aHMgZnJvbSBcIi4vY2VydC5wYXRoc1wiO1xuXG5leHBvcnQgY2xhc3MgQ2VydCB7XG4gICAgY2ZFbWFpbDpzdHJpbmc7XG4gICAgY2ZLZXk6c3RyaW5nO1xuICAgIHNzbERpcjpzdHJpbmc7XG4gICAgY2VydGlmaWNhdGVzUHJlc2VudDtcbiAgICBjZXJ0aWZpY2F0ZXNWYWxpZDtcbiAgICBnaXRPcmlnaW5SZXBvO1xuICAgIGNvbnN0cnVjdG9yKG9wdGlvbnNBcmc6e1xuICAgICAgICBjZkVtYWlsOnN0cmluZyxcbiAgICAgICAgY2ZLZXk6c3RyaW5nLFxuICAgICAgICBzc2xEaXI6c3RyaW5nLFxuICAgICAgICBnaXRPcmlnaW5SZXBvPzpzdHJpbmdcbiAgICB9KXtcbiAgICAgICAgdGhpcy5jZkVtYWlsID0gb3B0aW9uc0FyZy5jZkVtYWlsO1xuICAgICAgICB0aGlzLmNmS2V5ID0gb3B0aW9uc0FyZy5jZktleTtcbiAgICAgICAgdGhpcy5zc2xEaXIgPSBvcHRpb25zQXJnLnNzbERpcjtcbiAgICAgICAgdGhpcy5naXRPcmlnaW5SZXBvID0gb3B0aW9uc0FyZy5naXRPcmlnaW5SZXBvO1xuICAgIH07XG4gICAgZ2V0RG9tYWluQ2VydCgpe307XG59XG5cbmV4cG9ydCBjbGFzcyBDZXJ0aWZpY2F0ZSB7XG4gICAgZG9tYWluTmFtZTpzdHJpbmc7XG4gICAgY3JlYXRpb25EYXRlOkRhdGU7XG4gICAgZXhwaXJ5RGF0ZTpEYXRlO1xuICAgIGNvbnN0cnVjdG9yKCl7XG5cbiAgICB9O1xufSJdfQ== +//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxJQUFZLE9BQU8sV0FBTSxnQkFBZ0IsQ0FBQyxDQUFBO0FBQzFDLElBQVksS0FBSyxXQUFNLGNBQWMsQ0FBQyxDQUFBO0FBRXRDO0lBT0ksY0FBWSxVQUtYO1FBQ0csSUFBSSxDQUFDLE9BQU8sR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDO1FBQ2xDLElBQUksQ0FBQyxLQUFLLEdBQUcsVUFBVSxDQUFDLEtBQUssQ0FBQztRQUM5QixJQUFJLENBQUMsTUFBTSxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUM7UUFDaEMsSUFBSSxDQUFDLGFBQWEsR0FBRyxVQUFVLENBQUMsYUFBYSxDQUFDO1FBQzlDLElBQUksTUFBTSxHQUFHO1lBQ1QsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPO1lBQ3JCLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSztTQUNwQixDQUFBO1FBQ0QsT0FBTyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLEVBQUMsRUFBQyxRQUFRLEVBQUMsYUFBYSxFQUFDLFFBQVEsRUFBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUMsU0FBUyxDQUFDLEVBQUMsQ0FBQyxDQUFDO0lBQ3ZJLENBQUM7O0lBQ0QsNEJBQWEsR0FBYixVQUFjLGFBQW9CO1FBQzlCLElBQUksSUFBSSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDN0IsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUN6RCxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxZQUFZLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3BELE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFlBQVksR0FBRyxLQUFLLENBQUMsYUFBYSxHQUFHLFNBQVMsR0FBRyxhQUFhLEdBQUcsZ0JBQWdCLEdBQUcsS0FBSyxDQUFDLFFBQVEsR0FBRyxNQUFNLEdBQUUsS0FBSyxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsQ0FBQztRQUN2SixNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztJQUN4QixDQUFDOztJQUNMLFdBQUM7QUFBRCxDQTlCQSxBQThCQyxJQUFBO0FBOUJZLFlBQUksT0E4QmhCLENBQUE7QUFFRDtJQUlJO0lBRUEsQ0FBQzs7SUFDTCxrQkFBQztBQUFELENBUEEsQUFPQyxJQUFBO0FBUFksbUJBQVcsY0FPdkIsQ0FBQSIsImZpbGUiOiJpbmRleC5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIHBsdWdpbnMgZnJvbSBcIi4vY2VydC5wbHVnaW5zXCI7XG5pbXBvcnQgKiBhcyBwYXRocyBmcm9tIFwiLi9jZXJ0LnBhdGhzXCI7XG5cbmV4cG9ydCBjbGFzcyBDZXJ0IHtcbiAgICBjZkVtYWlsOnN0cmluZztcbiAgICBjZktleTpzdHJpbmc7XG4gICAgc3NsRGlyOnN0cmluZztcbiAgICBjZXJ0aWZpY2F0ZXNQcmVzZW50O1xuICAgIGNlcnRpZmljYXRlc1ZhbGlkO1xuICAgIGdpdE9yaWdpblJlcG87XG4gICAgY29uc3RydWN0b3Iob3B0aW9uc0FyZzp7XG4gICAgICAgIGNmRW1haWw6c3RyaW5nLFxuICAgICAgICBjZktleTpzdHJpbmcsXG4gICAgICAgIHNzbERpcjpzdHJpbmcsXG4gICAgICAgIGdpdE9yaWdpblJlcG8/OnN0cmluZ1xuICAgIH0pe1xuICAgICAgICB0aGlzLmNmRW1haWwgPSBvcHRpb25zQXJnLmNmRW1haWw7XG4gICAgICAgIHRoaXMuY2ZLZXkgPSBvcHRpb25zQXJnLmNmS2V5O1xuICAgICAgICB0aGlzLnNzbERpciA9IG9wdGlvbnNBcmcuc3NsRGlyO1xuICAgICAgICB0aGlzLmdpdE9yaWdpblJlcG8gPSBvcHRpb25zQXJnLmdpdE9yaWdpblJlcG87XG4gICAgICAgIGxldCBjb25maWcgPSB7XG4gICAgICAgICAgICBjZkVtYWlsOiB0aGlzLmNmRW1haWwsXG4gICAgICAgICAgICBjZktleTogdGhpcy5jZktleVxuICAgICAgICB9XG4gICAgICAgIHBsdWdpbnMuc21hcnRmaWxlLm1lbW9yeS50b0ZzU3luYyhKU09OLnN0cmluZ2lmeShjb25maWcpLHtmaWxlTmFtZTpcImNvbmZpZy5qc29uXCIsZmlsZVBhdGg6cGx1Z2lucy5wYXRoLmpvaW4oX19kaXJuYW1lLFwiYXNzZXRzL1wiKX0pO1xuICAgIH07XG4gICAgZ2V0RG9tYWluQ2VydChkb21haW5OYW1lQXJnOnN0cmluZyl7XG4gICAgICAgIGxldCBkb25lID0gcGx1Z2lucy5xLmRlZmVyKCk7XG4gICAgICAgIHBsdWdpbnMuc2hlbGxqcy5leGVjKFwiY2htb2QgNzAwIFwiICsgcGF0aHMubGV0c2VuY3J5cHRTaCk7XG4gICAgICAgIHBsdWdpbnMuc2hlbGxqcy5leGVjKFwiY2htb2QgNzAwIFwiICsgcGF0aHMuY2VydEhvb2spO1xuICAgICAgICBwbHVnaW5zLnNoZWxsanMuZXhlYyhcImJhc2ggLWMgXFxcIlwiICsgcGF0aHMubGV0c2VuY3J5cHRTaCArIFwiIC1jIC1kIFwiICsgZG9tYWluTmFtZUFyZyArIFwiIC10IGRucy0wMSAtayBcIiArIHBhdGhzLmNlcnRIb29rICsgXCIgLW8gXCIrIHBhdGhzLnNzbERpciArIFwiXFxcIlwiKTtcbiAgICAgICAgcmV0dXJuIGRvbmUucHJvbWlzZTtcbiAgICB9O1xufVxuXG5leHBvcnQgY2xhc3MgQ2VydGlmaWNhdGUge1xuICAgIGRvbWFpbk5hbWU6c3RyaW5nO1xuICAgIGNyZWF0aW9uRGF0ZTpEYXRlO1xuICAgIGV4cGlyeURhdGU6RGF0ZTtcbiAgICBjb25zdHJ1Y3Rvcigpe1xuXG4gICAgfTtcbn0iXX0= diff --git a/dist/install.d.ts b/dist/install.d.ts index e69de29..1dbcc9f 100644 --- a/dist/install.d.ts +++ b/dist/install.d.ts @@ -0,0 +1 @@ +export declare let startInstall: () => any; diff --git a/dist/install.js b/dist/install.js index 60e4edb..132595a 100644 --- a/dist/install.js +++ b/dist/install.js @@ -1,12 +1,20 @@ "use strict"; -var beautylog = require("beautylog"); -var path = require("path"); -var smartfile = require("smartfile"); -var fs = require("fs-extra"); -beautylog.info("installing letsencrypt.sh locally..."); -fs.ensureDir(path.join(__dirname, "assets/")); -smartfile.remote.toFs("https://raw.githubusercontent.com/lukas2511/letsencrypt.sh/master/letsencrypt.sh", path.join(__dirname, "assets/", "le.sh")).then(function () { - beautylog.success("Done!"); -}); +var plugins = require("./cert.plugins"); +var paths = require("./cert.paths"); +exports.startInstall = function () { + var done = plugins.q.defer(); + plugins.beautylog.info("installing letsencrypt.sh locally..."); + plugins.fs.ensureDir(plugins.path.join(__dirname, "assets/")); + plugins.smartfile.remote.toFs("https://raw.githubusercontent.com/lukas2511/letsencrypt.sh/master/letsencrypt.sh", paths.letsencryptSh).then(function () { + plugins.beautylog.success("Done!"); + done.resolve(); + }); + return done.promise; +}; +var smartcli = new plugins.smartcli.Smartcli(); +smartcli.addCommand({ + commandName: "install" +}).then(exports.startInstall); +smartcli.startParse(); -//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluc3RhbGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLElBQVksU0FBUyxXQUFNLFdBQVcsQ0FBQyxDQUFBO0FBQ3ZDLElBQVksSUFBSSxXQUFNLE1BQU0sQ0FBQyxDQUFBO0FBQzdCLElBQVksU0FBUyxXQUFNLFdBQVcsQ0FBQyxDQUFBO0FBQ3ZDLElBQUksRUFBRSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztBQUM3QixTQUFTLENBQUMsSUFBSSxDQUFDLHNDQUFzQyxDQUFDLENBQUM7QUFFdkQsRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO0FBQzdDLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUNqQixrRkFBa0YsRUFDbEYsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUMsU0FBUyxFQUFDLE9BQU8sQ0FBQyxDQUN6QyxDQUFDLElBQUksQ0FBQztJQUNILFNBQVMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDL0IsQ0FBQyxDQUFDLENBQUMiLCJmaWxlIjoiaW5zdGFsbC5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGJlYXV0eWxvZyBmcm9tIFwiYmVhdXR5bG9nXCI7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgKiBhcyBzbWFydGZpbGUgZnJvbSBcInNtYXJ0ZmlsZVwiO1xubGV0IGZzID0gcmVxdWlyZShcImZzLWV4dHJhXCIpO1xuYmVhdXR5bG9nLmluZm8oXCJpbnN0YWxsaW5nIGxldHNlbmNyeXB0LnNoIGxvY2FsbHkuLi5cIik7XG5cbmZzLmVuc3VyZURpcihwYXRoLmpvaW4oX19kaXJuYW1lLFwiYXNzZXRzL1wiKSk7XG5zbWFydGZpbGUucmVtb3RlLnRvRnMoXG4gICAgXCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbHVrYXMyNTExL2xldHNlbmNyeXB0LnNoL21hc3Rlci9sZXRzZW5jcnlwdC5zaFwiLFxuICAgIHBhdGguam9pbihfX2Rpcm5hbWUsXCJhc3NldHMvXCIsXCJsZS5zaFwiKVxuKS50aGVuKCgpID0+IHtcbiAgICBiZWF1dHlsb2cuc3VjY2VzcyhcIkRvbmUhXCIpO1xufSk7Il19 +//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluc3RhbGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLElBQVksT0FBTyxXQUFNLGdCQUFnQixDQUFDLENBQUE7QUFDMUMsSUFBWSxLQUFLLFdBQU0sY0FBYyxDQUFDLENBQUE7QUFFM0Isb0JBQVksR0FBRztJQUN0QixJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQzdCLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLHNDQUFzQyxDQUFDLENBQUM7SUFFL0QsT0FBTyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDOUQsT0FBTyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUN6QixrRkFBa0YsRUFDbEYsS0FBSyxDQUFDLGFBQWEsQ0FDdEIsQ0FBQyxJQUFJLENBQUM7UUFDSCxPQUFPLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNuQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDbkIsQ0FBQyxDQUFDLENBQUM7SUFDSCxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztBQUN4QixDQUFDLENBQUM7QUFFRixJQUFJLFFBQVEsR0FBRyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7QUFDL0MsUUFBUSxDQUFDLFVBQVUsQ0FBQztJQUNoQixXQUFXLEVBQUMsU0FBUztDQUN4QixDQUFDLENBQUMsSUFBSSxDQUFDLG9CQUFZLENBQUMsQ0FBQztBQUN0QixRQUFRLENBQUMsVUFBVSxFQUFFLENBQUMiLCJmaWxlIjoiaW5zdGFsbC5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIHBsdWdpbnMgZnJvbSBcIi4vY2VydC5wbHVnaW5zXCI7XG5pbXBvcnQgKiBhcyBwYXRocyBmcm9tIFwiLi9jZXJ0LnBhdGhzXCI7XG5cbmV4cG9ydCBsZXQgc3RhcnRJbnN0YWxsID0gKCkgPT4ge1xuICAgIGxldCBkb25lID0gcGx1Z2lucy5xLmRlZmVyKCk7XG4gICAgcGx1Z2lucy5iZWF1dHlsb2cuaW5mbyhcImluc3RhbGxpbmcgbGV0c2VuY3J5cHQuc2ggbG9jYWxseS4uLlwiKTtcblxuICAgIHBsdWdpbnMuZnMuZW5zdXJlRGlyKHBsdWdpbnMucGF0aC5qb2luKF9fZGlybmFtZSwgXCJhc3NldHMvXCIpKTtcbiAgICBwbHVnaW5zLnNtYXJ0ZmlsZS5yZW1vdGUudG9GcyhcbiAgICAgICAgXCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbHVrYXMyNTExL2xldHNlbmNyeXB0LnNoL21hc3Rlci9sZXRzZW5jcnlwdC5zaFwiLFxuICAgICAgICBwYXRocy5sZXRzZW5jcnlwdFNoXG4gICAgKS50aGVuKCgpID0+IHtcbiAgICAgICAgcGx1Z2lucy5iZWF1dHlsb2cuc3VjY2VzcyhcIkRvbmUhXCIpO1xuICAgICAgICBkb25lLnJlc29sdmUoKTtcbiAgICB9KTtcbiAgICByZXR1cm4gZG9uZS5wcm9taXNlO1xufTtcblxubGV0IHNtYXJ0Y2xpID0gbmV3IHBsdWdpbnMuc21hcnRjbGkuU21hcnRjbGkoKTtcbnNtYXJ0Y2xpLmFkZENvbW1hbmQoe1xuICAgIGNvbW1hbmROYW1lOlwiaW5zdGFsbFwiXG59KS50aGVuKHN0YXJ0SW5zdGFsbCk7XG5zbWFydGNsaS5zdGFydFBhcnNlKCk7Il19 diff --git a/package.json b/package.json index 541e4eb..3eb9029 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "dist/index.js", "scripts": { "test": "(npmts)", - "install": "node dist/install.js" + "install": "node dist/install.js install" }, "repository": { "type": "git", @@ -25,14 +25,15 @@ "homepage": "https://gitlab.com/pushrocks/cert#readme", "dependencies": { "beautylog": "^5.0.12", - "cflare": "0.0.6", + "cflare": "0.0.7", "fs-extra": "^0.30.0", "letsencrypt": "^1.4.4", "q": "^1.4.1", - "smartcli": "^1.0.2", + "shelljs": "^0.7.0", + "smartcli": "^1.0.4", "smartfile": "^3.0.10", "smartgit": "0.0.10", - "smartstring": "^2.0.9", + "smartstring": "^2.0.10", "typings-global": "^1.0.3" }, "devDependencies": { diff --git a/test/test.js b/test/test.js index e16d176..a1377ef 100644 --- a/test/test.js +++ b/test/test.js @@ -2,6 +2,35 @@ require("typings-test"); require("should"); var qenv_1 = require("qenv"); +var install_1 = require("../dist/install"); +var cert = require("../dist/index"); var testQenv = new qenv_1.Qenv(process.cwd(), process.cwd() + "/.nogit"); +var testCert; +describe("cert", function () { + describe("install", function () { + it("should download letsencrypt.sh", function (done) { + this.timeout(5000); + install_1.startInstall().then(function () { + done(); + }); + }); + }); + describe("Cert", function () { + it("should create a new cert", function () { + testCert = new cert.Cert({ + cfEmail: process.env.CF_EMAIL, + cfKey: process.env.CF_KEY, + sslDir: "" + }); + testCert.should.be.instanceof(cert.Cert); + }); + it("should get a valid certificate", function (done) { + this.timeout(120000); + testCert.getDomainCert("sub2.bleu.de").then(function () { + done(); + }); + }); + }); +}); -//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLFFBQU8sY0FBYyxDQUFDLENBQUE7QUFDdEIsUUFBTyxRQUFRLENBQUMsQ0FBQTtBQUVoQixxQkFBbUIsTUFBTSxDQUFDLENBQUE7QUFFMUIsSUFBSSxRQUFRLEdBQUcsSUFBSSxXQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLE9BQU8sQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FBQyIsImZpbGUiOiJ0ZXN0LmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFwidHlwaW5ncy10ZXN0XCI7XG5pbXBvcnQgXCJzaG91bGRcIjtcbmltcG9ydCAqIGFzIGNlcnQgZnJvbSBcIi4uL2Rpc3QvaW5kZXhcIjtcbmltcG9ydCB7UWVudn0gZnJvbSBcInFlbnZcIjtcblxubGV0IHRlc3RRZW52ID0gbmV3IFFlbnYocHJvY2Vzcy5jd2QoKSwgcHJvY2Vzcy5jd2QoKSArIFwiLy5ub2dpdFwiKTsiXX0= +//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLFFBQU8sY0FBYyxDQUFDLENBQUE7QUFDdEIsUUFBTyxRQUFRLENBQUMsQ0FBQTtBQUNoQixxQkFBbUIsTUFBTSxDQUFDLENBQUE7QUFFMUIsd0JBQTJCLGlCQUFpQixDQUFDLENBQUE7QUFDN0MsSUFBWSxJQUFJLFdBQU0sZUFBZSxDQUFDLENBQUE7QUFHdEMsSUFBSSxRQUFRLEdBQUcsSUFBSSxXQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLE9BQU8sQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FBQztBQUVsRSxJQUFJLFFBQWtCLENBQUM7QUFFdkIsUUFBUSxDQUFDLE1BQU0sRUFBQztJQUNaLFFBQVEsQ0FBQyxTQUFTLEVBQUM7UUFDZixFQUFFLENBQUMsZ0NBQWdDLEVBQUMsVUFBUyxJQUFJO1lBQzdDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDbkIsc0JBQVksRUFBRSxDQUFDLElBQUksQ0FBQztnQkFDaEIsSUFBSSxFQUFFLENBQUM7WUFDWCxDQUFDLENBQUMsQ0FBQTtRQUNOLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENBQUE7SUFDRixRQUFRLENBQUMsTUFBTSxFQUFDO1FBQ1osRUFBRSxDQUFDLDBCQUEwQixFQUFDO1lBQzFCLFFBQVEsR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUM7Z0JBQ3JCLE9BQU8sRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVE7Z0JBQzdCLEtBQUssRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU07Z0JBQ3pCLE1BQU0sRUFBRSxFQUFFO2FBQ2IsQ0FBQyxDQUFDO1lBQ0gsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM3QyxDQUFDLENBQUMsQ0FBQTtRQUNGLEVBQUUsQ0FBQyxnQ0FBZ0MsRUFBQyxVQUFTLElBQUk7WUFDN0MsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNyQixRQUFRLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBQyxDQUFDLElBQUksQ0FBQztnQkFDeEMsSUFBSSxFQUFFLENBQUM7WUFDWCxDQUFDLENBQUMsQ0FBQztRQUNQLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENBQUE7QUFDTixDQUFDLENBQUMsQ0FBQyIsImZpbGUiOiJ0ZXN0LmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFwidHlwaW5ncy10ZXN0XCI7XG5pbXBvcnQgXCJzaG91bGRcIjtcbmltcG9ydCB7UWVudn0gZnJvbSBcInFlbnZcIjtcblxuaW1wb3J0IHtzdGFydEluc3RhbGx9IGZyb20gXCIuLi9kaXN0L2luc3RhbGxcIjtcbmltcG9ydCAqIGFzIGNlcnQgZnJvbSBcIi4uL2Rpc3QvaW5kZXhcIjtcblxuXG5sZXQgdGVzdFFlbnYgPSBuZXcgUWVudihwcm9jZXNzLmN3ZCgpLCBwcm9jZXNzLmN3ZCgpICsgXCIvLm5vZ2l0XCIpO1xuXG5sZXQgdGVzdENlcnQ6Y2VydC5DZXJ0O1xuXG5kZXNjcmliZShcImNlcnRcIixmdW5jdGlvbigpe1xuICAgIGRlc2NyaWJlKFwiaW5zdGFsbFwiLGZ1bmN0aW9uKCl7XG4gICAgICAgIGl0KFwic2hvdWxkIGRvd25sb2FkIGxldHNlbmNyeXB0LnNoXCIsZnVuY3Rpb24oZG9uZSl7XG4gICAgICAgICAgICB0aGlzLnRpbWVvdXQoNTAwMCk7XG4gICAgICAgICAgICBzdGFydEluc3RhbGwoKS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICBkb25lKCk7XG4gICAgICAgICAgICB9KVxuICAgICAgICB9KVxuICAgIH0pXG4gICAgZGVzY3JpYmUoXCJDZXJ0XCIsZnVuY3Rpb24oKXtcbiAgICAgICAgaXQoXCJzaG91bGQgY3JlYXRlIGEgbmV3IGNlcnRcIixmdW5jdGlvbigpe1xuICAgICAgICAgICAgdGVzdENlcnQgPSBuZXcgY2VydC5DZXJ0KHtcbiAgICAgICAgICAgICAgICBjZkVtYWlsOiBwcm9jZXNzLmVudi5DRl9FTUFJTCxcbiAgICAgICAgICAgICAgICBjZktleTogcHJvY2Vzcy5lbnYuQ0ZfS0VZLFxuICAgICAgICAgICAgICAgIHNzbERpcjogXCJcIlxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB0ZXN0Q2VydC5zaG91bGQuYmUuaW5zdGFuY2VvZihjZXJ0LkNlcnQpO1xuICAgICAgICB9KVxuICAgICAgICBpdChcInNob3VsZCBnZXQgYSB2YWxpZCBjZXJ0aWZpY2F0ZVwiLGZ1bmN0aW9uKGRvbmUpe1xuICAgICAgICAgICAgdGhpcy50aW1lb3V0KDEyMDAwMCk7XG4gICAgICAgICAgICB0ZXN0Q2VydC5nZXREb21haW5DZXJ0KFwic3ViMi5ibGV1LmRlXCIpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgIGRvbmUoKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KVxuICAgIH0pXG59KTsiXX0= diff --git a/test/test.ts b/test/test.ts index 8de9922..afc33ca 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,7 +1,38 @@ import "typings-test"; import "should"; -import * as cert from "../dist/index"; import {Qenv} from "qenv"; +import {startInstall} from "../dist/install"; +import * as cert from "../dist/index"; + + let testQenv = new Qenv(process.cwd(), process.cwd() + "/.nogit"); +let testCert:cert.Cert; + +describe("cert",function(){ + describe("install",function(){ + it("should download letsencrypt.sh",function(done){ + this.timeout(5000); + startInstall().then(() => { + done(); + }) + }) + }) + describe("Cert",function(){ + it("should create a new cert",function(){ + testCert = new cert.Cert({ + cfEmail: process.env.CF_EMAIL, + cfKey: process.env.CF_KEY, + sslDir: "" + }); + testCert.should.be.instanceof(cert.Cert); + }) + it("should get a valid certificate",function(done){ + this.timeout(120000); + testCert.getDomainCert("sub2.bleu.de").then(() => { + done(); + }); + }) + }) +}); \ No newline at end of file diff --git a/ts/cert.hook.ts b/ts/cert.hook.ts index 333cdb9..d6b1056 100644 --- a/ts/cert.hook.ts +++ b/ts/cert.hook.ts @@ -1,3 +1,58 @@ -import * as smartcli from "smartcli"; -import * as cflare from "cflare"; +#!/usr/bin/env node +// the shebang line above makes sure this script will get interpreted by node +import "typings-global"; +import * as plugins from "./cert.plugins"; +import * as paths from "./cert.paths"; + +let smartcli = new plugins.smartcli.Smartcli(); + +let config = plugins.smartfile.local.toObjectSync(paths.config); +let cflare = new plugins.cflare.CflareAccount(); +cflare.auth({ + email: config.cfEmail, + key: config.cfKey +}); + +let setChallenge = (domainNameArg: string, challengeArg: string) => { + let done = plugins.q.defer(); + cflare.createRecord(prefixName(domainNameArg), "TXT", challengeArg).then(() => { + cooldown().then(() => { + done.resolve(); + }); + }); + return done.promise; +} + +let cleanChallenge = (domainNameArg) => { + let done = plugins.q.defer(); + cflare.removeRecord(prefixName(domainNameArg), "TXT"); + return done.promise; +} + +let cooldown = () => { + let done = plugins.q.defer(); + console.log("Cooling down!"); + setTimeout(() => { + done.resolve(); + }, 20000) + return done.promise; +} + +let prefixName = (domainNameArg: string): string => { + return "_acme-challenge." + domainNameArg; +} + +smartcli.addCommand({ + commandName: "deploy_challenge" +}).then((argv) => { + setChallenge(argv._[1], argv._[3]); +}); + +smartcli.addCommand({ + commandName: "clean_challenge" +}).then((argv) => { + cleanChallenge(argv._[1]); +}); + +smartcli.startParse(); diff --git a/ts/cert.paths.ts b/ts/cert.paths.ts index 68d0fa0..1f5ac2c 100644 --- a/ts/cert.paths.ts +++ b/ts/cert.paths.ts @@ -1,3 +1,7 @@ import "typings-global"; -export import path = require("path"); +import * as plugins from "./cert.plugins"; +export let certHook = plugins.path.join(__dirname,"cert.hook.js"); +export let config = plugins.path.join(__dirname,"assets/config.json"); +export let letsencryptSh = plugins.path.join(__dirname,"assets/letsencrypt.sh"); +export let sslDir = plugins.path.join(__dirname,"/assets/certs"); \ No newline at end of file diff --git a/ts/cert.plugins.ts b/ts/cert.plugins.ts index 253e3b3..03bbe3e 100644 --- a/ts/cert.plugins.ts +++ b/ts/cert.plugins.ts @@ -1,6 +1,11 @@ import "typings-global"; +export import beautylog = require("beautylog"); +export import cflare = require("cflare"); +export let fs = require("fs-extra"); export import path = require("path"); export let q = require("q"); +export let shelljs = require("shelljs"); +export import smartcli = require("smartcli"); export import smartfile = require("smartfile"); export import smartstring = require("smartstring"); diff --git a/ts/index.ts b/ts/index.ts index 0c9a7b1..d75b021 100644 --- a/ts/index.ts +++ b/ts/index.ts @@ -1,3 +1,4 @@ +import * as plugins from "./cert.plugins"; import * as paths from "./cert.paths"; export class Cert { @@ -17,8 +18,20 @@ export class Cert { this.cfKey = optionsArg.cfKey; this.sslDir = optionsArg.sslDir; this.gitOriginRepo = optionsArg.gitOriginRepo; + let config = { + cfEmail: this.cfEmail, + cfKey: this.cfKey + } + plugins.smartfile.memory.toFsSync(JSON.stringify(config),{fileName:"config.json",filePath:plugins.path.join(__dirname,"assets/")}); + }; + getDomainCert(domainNameArg:string){ + let done = plugins.q.defer(); + plugins.shelljs.exec("chmod 700 " + paths.letsencryptSh); + plugins.shelljs.exec("chmod 700 " + paths.certHook); + plugins.shelljs.exec("bash -c \"" + paths.letsencryptSh + " -c -d " + domainNameArg + " -t dns-01 -k " + paths.certHook + " -o "+ paths.sslDir + "\""); + done.resolve(); + return done.promise; }; - getDomainCert(){}; } export class Certificate { diff --git a/ts/install.ts b/ts/install.ts index 81a06a5..a06ca40 100644 --- a/ts/install.ts +++ b/ts/install.ts @@ -1,13 +1,23 @@ -import * as beautylog from "beautylog"; -import * as path from "path"; -import * as smartfile from "smartfile"; -let fs = require("fs-extra"); -beautylog.info("installing letsencrypt.sh locally..."); +import * as plugins from "./cert.plugins"; +import * as paths from "./cert.paths"; -fs.ensureDir(path.join(__dirname,"assets/")); -smartfile.remote.toFs( - "https://raw.githubusercontent.com/lukas2511/letsencrypt.sh/master/letsencrypt.sh", - path.join(__dirname,"assets/","le.sh") -).then(() => { - beautylog.success("Done!"); -}); \ No newline at end of file +export let startInstall = () => { + let done = plugins.q.defer(); + plugins.beautylog.info("installing letsencrypt.sh locally..."); + + plugins.fs.ensureDir(plugins.path.join(__dirname, "assets/")); + plugins.smartfile.remote.toFs( + "https://raw.githubusercontent.com/lukas2511/letsencrypt.sh/master/letsencrypt.sh", + paths.letsencryptSh + ).then(() => { + plugins.beautylog.success("Done!"); + done.resolve(); + }); + return done.promise; +}; + +let smartcli = new plugins.smartcli.Smartcli(); +smartcli.addCommand({ + commandName:"install" +}).then(startInstall); +smartcli.startParse(); \ No newline at end of file