Remove unneeded Go code, update dependencies
parent
30c7ddba80
commit
4ecdedadf7
@ -1,7 +1,5 @@
|
||||
*.pem
|
||||
.*.swp
|
||||
/translate.*.toml
|
||||
/.idea/
|
||||
/example_ca/
|
||||
/node_modules/
|
||||
/public/
|
||||
|
@ -1,71 +0,0 @@
|
||||
[CSRButtonLabel]
|
||||
hash = "sha1-7f7bcb57602a96a49c8df4868fad7b81992e0734"
|
||||
other = "Zertifikats-Signier-Anfrage erzeugen"
|
||||
|
||||
[CSRGenTitle]
|
||||
hash = "sha1-f1a8f21b12fe51250da4a11f1c6ab28eab69b69d"
|
||||
other = "CSR-Erzeugung im Browser"
|
||||
|
||||
[DownloadDescription]
|
||||
hash = "sha1-f4a7826398e5c57c7feb4709ee939ea655f05469"
|
||||
other = "Dein Schlüsselmaterial ist bereit zum Herunterladen. Die herunterladbare Datei enthält deinen privaten Schlüssel und dein Zertifikat verschlüsselt mit deinem Passwort. Du kannst die Datei jetzt verwenden, um dein Zertifikat in deinem Browser oder anderen Anwendungen zu installieren."
|
||||
|
||||
[DownloadLabel]
|
||||
hash = "sha1-a479c9c34e878d07b4d67a73a48f432ad7dc53c8"
|
||||
other = "Herunterladen"
|
||||
|
||||
["JavaScript.Certificate.Received"]
|
||||
hash = "sha1-217622c21b50fcfb864802155080be482c285456"
|
||||
other = "Zertifikat von der CA erhalten"
|
||||
|
||||
["JavaScript.Certificate.Waiting"]
|
||||
hash = "sha1-0a528daa78d850d2c9360cdec82f6f849ffb6bcf"
|
||||
other = "Warte auf Zertifikat ..."
|
||||
|
||||
["JavaScript.KeyGen.Generated"]
|
||||
hash = "sha1-34cdfcdc837e3fc052733a3588cc3923b793103e"
|
||||
other = "Schlüssel in __seconds__ Sekunden erzeugt"
|
||||
|
||||
["JavaScript.KeyGen.Running"]
|
||||
hash = "sha1-fd272f37118fe10395f6238a3eae94685b5f8cf1"
|
||||
other = "Schlüsselerzeugung läuft seit __seconds__ Sekunden"
|
||||
|
||||
["JavaScript.KeyGen.Started"]
|
||||
hash = "sha1-e68739d705d5eb16317984a95a486fb9ff9bae6d"
|
||||
other = "Schlüsselerzeugung gestartet"
|
||||
|
||||
[NameHelpText]
|
||||
hash = "sha1-52b81217549e37d161090a04b7f84223a270928e"
|
||||
other = "Gib deinen Namen so ein, wie er im Zertifikat erscheinen soll"
|
||||
|
||||
[NameLabel]
|
||||
hash = "sha1-ab42293e29e1ffb306c1403dd95144d664853a60"
|
||||
other = "Dein Name"
|
||||
|
||||
[PasswordLabel]
|
||||
hash = "sha1-2b5e8edbf45819afdfa973c224b6b02d699e60de"
|
||||
other = "Passwort für dein Client-Zertifikat"
|
||||
|
||||
[RSA2048Label]
|
||||
hash = "sha1-2b1e7b638c31426d30d7e4bdebadbaa07d7521b0"
|
||||
other = "2048 Bit (nicht empfohlen)"
|
||||
|
||||
[RSA3072Label]
|
||||
hash = "sha1-97d1a8f9e8c5cf1f473b4a6fa0b5c39905f0f747"
|
||||
other = "3072 Bit"
|
||||
|
||||
[RSA4096Label]
|
||||
hash = "sha1-b14d7490195ac7f2d649f3b75dd2fe0daea53967"
|
||||
other = "4096 Bit"
|
||||
|
||||
[RSAHelpText]
|
||||
hash = "sha1-82511ecf2909ba189d7b16a828fce97c9359fad1"
|
||||
other = "In Deinem Browser wird ein RSA-Schlüsselpaar erzeugt. Größere Schlüssellängen bieten eine erhöhte Sicherheit, benötigen aber bei der Erzeugung mehr Zeit."
|
||||
|
||||
[RSAKeySizeLabel]
|
||||
hash = "sha1-bd446df78ad62000d6516a95594a24b98688e1fa"
|
||||
other = "RSA-Schlüssellänge"
|
||||
|
||||
[StatusLoading]
|
||||
hash = "sha1-530afa5bce434b05e3a10e83ff2567f7f8622af9"
|
||||
other = "Lade ..."
|
@ -1,71 +0,0 @@
|
||||
[CSRButtonLabel]
|
||||
hash = "sha1-7f7bcb57602a96a49c8df4868fad7b81992e0734"
|
||||
other = "Generate signing request"
|
||||
|
||||
[CSRGenTitle]
|
||||
hash = "sha1-f1a8f21b12fe51250da4a11f1c6ab28eab69b69d"
|
||||
other = "CSR generation in browser"
|
||||
|
||||
[DownloadDescription]
|
||||
hash = "sha1-f4a7826398e5c57c7feb4709ee939ea655f05469"
|
||||
other = "Your key material is ready for download. The downloadable file contains your private key and your certificate encrypted with your password. You can now use the file to install your certificate in your browser or other applications."
|
||||
|
||||
[DownloadLabel]
|
||||
hash = "sha1-a479c9c34e878d07b4d67a73a48f432ad7dc53c8"
|
||||
other = "Download"
|
||||
|
||||
["JavaScript.Certificate.Received"]
|
||||
hash = "sha1-217622c21b50fcfb864802155080be482c285456"
|
||||
other = "received certificate from CA"
|
||||
|
||||
["JavaScript.Certificate.Waiting"]
|
||||
hash = "sha1-0a528daa78d850d2c9360cdec82f6f849ffb6bcf"
|
||||
other = "waiting for certificate ..."
|
||||
|
||||
["JavaScript.KeyGen.Generated"]
|
||||
hash = "sha1-34cdfcdc837e3fc052733a3588cc3923b793103e"
|
||||
other = "key generated in __seconds__ seconds"
|
||||
|
||||
["JavaScript.KeyGen.Running"]
|
||||
hash = "sha1-fd272f37118fe10395f6238a3eae94685b5f8cf1"
|
||||
other = "key generation running for __seconds__ seconds"
|
||||
|
||||
["JavaScript.KeyGen.Started"]
|
||||
hash = "sha1-e68739d705d5eb16317984a95a486fb9ff9bae6d"
|
||||
other = "started key generation"
|
||||
|
||||
[NameHelpText]
|
||||
hash = "sha1-52b81217549e37d161090a04b7f84223a270928e"
|
||||
other = "Please input your name as it should be added to your certificate"
|
||||
|
||||
[NameLabel]
|
||||
hash = "sha1-ab42293e29e1ffb306c1403dd95144d664853a60"
|
||||
other = "Your name"
|
||||
|
||||
[PasswordLabel]
|
||||
hash = "sha1-2b5e8edbf45819afdfa973c224b6b02d699e60de"
|
||||
other = "Password for your client certificate"
|
||||
|
||||
[RSA2048Label]
|
||||
hash = "sha1-2b1e7b638c31426d30d7e4bdebadbaa07d7521b0"
|
||||
other = "2048 Bit (not recommended)"
|
||||
|
||||
[RSA3072Label]
|
||||
hash = "sha1-97d1a8f9e8c5cf1f473b4a6fa0b5c39905f0f747"
|
||||
other = "3072 Bit"
|
||||
|
||||
[RSA4096Label]
|
||||
hash = "sha1-b14d7490195ac7f2d649f3b75dd2fe0daea53967"
|
||||
other = "4096 Bit"
|
||||
|
||||
[RSAHelpText]
|
||||
hash = "sha1-82511ecf2909ba189d7b16a828fce97c9359fad1"
|
||||
other = "An RSA key pair will be generated in your browser. Longer key sizes provide better security but take longer to generate."
|
||||
|
||||
[RSAKeySizeLabel]
|
||||
hash = "sha1-bd446df78ad62000d6516a95594a24b98688e1fa"
|
||||
other = "RSA Key Size"
|
||||
|
||||
[StatusLoading]
|
||||
hash = "sha1-530afa5bce434b05e3a10e83ff2567f7f8622af9"
|
||||
other = "Loading ..."
|
@ -1,18 +0,0 @@
|
||||
CSRButtonLabel = "Generate signing request"
|
||||
CSRGenTitle = "CSR generation in browser"
|
||||
DownloadDescription = "Your key material is ready for download. The downloadable file contains your private key and your certificate encrypted with your password. You can now use the file to install your certificate in your browser or other applications."
|
||||
DownloadLabel = "Download"
|
||||
"JavaScript.Certificate.Received" = "received certificate from CA"
|
||||
"JavaScript.Certificate.Waiting" = "waiting for certificate ..."
|
||||
"JavaScript.KeyGen.Generated" = "key generated in __seconds__ seconds"
|
||||
"JavaScript.KeyGen.Running" = "key generation running for __seconds__ seconds"
|
||||
"JavaScript.KeyGen.Started" = "started key generation"
|
||||
NameHelpText = "Please input your name as it should be added to your certificate"
|
||||
NameLabel = "Your name"
|
||||
PasswordLabel = "Password for your client certificate"
|
||||
RSA2048Label = "2048 Bit (not recommended)"
|
||||
RSA3072Label = "3072 Bit"
|
||||
RSA4096Label = "4096 Bit"
|
||||
RSAHelpText = "An RSA key pair will be generated in your browser. Longer key sizes provide better security but take longer to generate."
|
||||
RSAKeySizeLabel = "RSA Key Size"
|
||||
StatusLoading = "Loading ..."
|
@ -1,140 +0,0 @@
|
||||
extensions = v3_ext
|
||||
|
||||
[ca]
|
||||
default_ca = sub_ca
|
||||
|
||||
[rootca]
|
||||
dir = ./example_ca/root
|
||||
certs = $dir/certs
|
||||
crl_dir = $dir/crl
|
||||
database = $dir/index.txt
|
||||
serial = $dir/serial
|
||||
new_certs_dir = $dir/newcerts
|
||||
|
||||
crl = $dir/crl.pem
|
||||
certificate = $dir/ca.crt.pem
|
||||
private_key = $dir/private/ca.key.pem
|
||||
RANDFILE = $dir/private/.rand
|
||||
|
||||
policy = policy_any
|
||||
unique_subject = no
|
||||
email_in_dn = no
|
||||
copy_extensions = none
|
||||
|
||||
default_md = sha256
|
||||
default_days = 1825
|
||||
default_crl_days = 30
|
||||
|
||||
[sub_ca]
|
||||
dir = ./example_ca/sub
|
||||
certs = $dir/certs
|
||||
crl_dir = $dir/crl
|
||||
database = $dir/index.txt
|
||||
serial = $dir/serial
|
||||
new_certs_dir = $dir/newcerts
|
||||
|
||||
crl = $dir/crl.pem
|
||||
certificate = $dir/ca.crt.pem
|
||||
private_key = $dir/private/ca.key.pem
|
||||
RANDFILE = $dir/private/.rand
|
||||
unique_subject = no
|
||||
email_in_dn = no
|
||||
|
||||
default_md = sha256
|
||||
default_days = 365
|
||||
default_crl_days = 30
|
||||
|
||||
[email_ca]
|
||||
dir = ./example_ca/email
|
||||
certs = $dir/certs
|
||||
crl_dir = $dir/crl
|
||||
database = $dir/index.txt
|
||||
serial = $dir/serial
|
||||
new_certs_dir = $dir/newcerts
|
||||
|
||||
crl = $dir/crl.pem
|
||||
certificate = $dir/ca.crt.pem
|
||||
private_key = $dir/private/ca.key.pem
|
||||
RANDFILE = $dir/private/.rand
|
||||
unique_subject = no
|
||||
email_in_dn = no
|
||||
|
||||
default_md = sha256
|
||||
default_days = 365
|
||||
default_crl_days = 30
|
||||
|
||||
[policy_any]
|
||||
countryName = match
|
||||
stateOrProvinceName = optional
|
||||
organizationName = match
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
[policy_match]
|
||||
commonName = supplied
|
||||
|
||||
[email_ext]
|
||||
basicConstraints = critical,CA:false
|
||||
keyUsage = keyEncipherment,digitalSignature,nonRepudiation
|
||||
extendedKeyUsage = clientAuth,emailProtection
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always
|
||||
authorityInfoAccess = 1.3.6.1.5.5.7.48.2;URI:http://example.org/ca/root/ca.crt,OCSP;URI:http://ocsp.example.org/
|
||||
crlDistributionPoints = URI:http://crl.example.org/email.crl
|
||||
|
||||
[req]
|
||||
default_bits = 3072
|
||||
default_keyfile = privkey.pem
|
||||
distinguished_name = req_distinguished_name
|
||||
attributes = req_attributes
|
||||
x509_extensions = root_ca
|
||||
|
||||
[req_distinguished_name]
|
||||
countryName = Country Name (2 letter code)
|
||||
countryName_default = CH
|
||||
countryName_min = 2
|
||||
countryName_max = 2
|
||||
|
||||
localityName = Locality Name (eg, city)
|
||||
|
||||
organizationName = Organization Name (eg, company)
|
||||
organizationalUnitName = Organizational Unit Name (eg, section)
|
||||
|
||||
commonName = Common Name (e.g. server FQDN or YOUR name)
|
||||
commonName_max = 64
|
||||
|
||||
[req_attributes]
|
||||
|
||||
[root_ca]
|
||||
basicConstraints = critical,CA:true
|
||||
keyUsage = critical,keyCertSign,cRLSign
|
||||
subjectKeyIdentifier = hash
|
||||
|
||||
[ext_sub_ca]
|
||||
basicConstraints = critical,CA:true,pathlen:0
|
||||
keyUsage = critical,keyCertSign,cRLSign
|
||||
extendedKeyUsage = serverAuth,clientAuth
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always
|
||||
authorityInfoAccess = 1.3.6.1.5.5.7.48.2;URI:http://example.org/ca/root/ca.crt,OCSP;URI:http://ocsp.example.org/
|
||||
crlDistributionPoints = URI:http://crl.example.org/sub.crl
|
||||
certificatePolicies = @policy_sub_ca
|
||||
|
||||
[ext_email_ca]
|
||||
basicConstraints = critical,CA:true,pathlen:0
|
||||
keyUsage = critical,keyCertSign,cRLSign
|
||||
extendedKeyUsage = clientAuth,emailProtection
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always
|
||||
authorityInfoAccess = 1.3.6.1.5.5.7.48.2;URI:http://example.org/ca/root/ca.crt,OCSP;URI:http://ocsp.example.org/
|
||||
crlDistributionPoints = URI:http://crl.example.org/email.crl
|
||||
certificatePolicies = @policy_email_ca
|
||||
|
||||
[policy_sub_ca]
|
||||
policyIdentifier = 1.3.6.1.5.5.7.2.1
|
||||
CPS = http://example.org/ca/sub/cps.html
|
||||
|
||||
[policy_email_ca]
|
||||
policyIdentifier = 1.3.6.1.5.5.7.2.1
|
||||
CPS = http://example.org/ca/email/cps.html
|
@ -1,8 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "code.cacert.org/jandd/poc-browser-csr-generation/migrations"
|
||||
)
|
||||
|
||||
func main() {
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
module code.cacert.org/jandd/poc-browser-csr-generation
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.0.4
|
||||
github.com/gorilla/csrf v1.7.0
|
||||
github.com/nicksnyder/go-i18n/v2 v2.1.1
|
||||
github.com/pressly/goose v2.6.0+incompatible
|
||||
github.com/sirupsen/logrus v1.7.0
|
||||
golang.org/x/text v0.3.4
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
@ -1,40 +0,0 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs=
|
||||
github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/gorilla/csrf v1.7.0 h1:mMPjV5/3Zd460xCavIkppUdvnl5fPXMpv2uz2Zyg7/Y=
|
||||
github.com/gorilla/csrf v1.7.0/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.1.1 h1:ATCOanRDlrfKVB4WHAdJnLEqZtDmKYsweqsOUYflnBU=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.1.1/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pressly/goose v2.6.0+incompatible h1:3f8zIQ8rfgP9tyI0Hmcs2YNAqUCL1c+diLe3iU8Qd/k=
|
||||
github.com/pressly/goose v2.6.0+incompatible/go.mod h1:m+QHWCqxR3k8D9l7qfzuC/djtlfzxr34mozWDYEu1z8=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
@ -1,107 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/csrf"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type IndexHandler struct {
|
||||
bundle *i18n.Bundle
|
||||
}
|
||||
|
||||
func NewIndexHandler(bundle *i18n.Bundle) *IndexHandler {
|
||||
return &IndexHandler{bundle: bundle}
|
||||
}
|
||||
|
||||
func (i *IndexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
if r.URL.Path != "/" {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
localizer := i18n.NewLocalizer(i.bundle, r.Header.Get("Accept-Language"))
|
||||
csrGenTitle := localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "CSRGenTitle",
|
||||
Other: "CSR generation in browser",
|
||||
}})
|
||||
nameLabel := localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "NameLabel",
|
||||
Other: "Your name",
|
||||
}})
|
||||
nameHelpText := localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "NameHelpText",
|
||||
Other: "Please input your name as it should be added to your certificate",
|
||||
}})
|
||||
passwordLabel := localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "PasswordLabel",
|
||||
Other: "Password for your client certificate",
|
||||
}})
|
||||
rsaKeySizeLegend := localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "RSAKeySizeLabel",
|
||||
Other: "RSA Key Size",
|
||||
}})
|
||||
rsa3072Label := localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "RSA3072Label",
|
||||
Other: "3072 Bit",
|
||||
}})
|
||||
rsa2048Label := localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "RSA2048Label",
|
||||
Other: "2048 Bit (not recommended)",
|
||||
}})
|
||||
rsa4096Label := localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "RSA4096Label",
|
||||
Other: "4096 Bit",
|
||||
}})
|
||||
rsaHelpText := localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "RSAHelpText",
|
||||
Other: "An RSA key pair will be generated in your browser. Longer key" +
|
||||
" sizes provide better security but take longer to generate.",
|
||||
}})
|
||||
csrButtonLabel := localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "CSRButtonLabel",
|
||||
Other: "Generate signing request",
|
||||
}})
|
||||
statusLoading := localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "StatusLoading",
|
||||
Other: "Loading ...",
|
||||
}})
|
||||
downloadLabel := localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "DownloadLabel",
|
||||
Other: "Download",
|
||||
}})
|
||||
downloadDescription := localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "DownloadDescription",
|
||||
Other: "Your key material is ready for download. The downloadable file contains your private key and your" +
|
||||
" certificate encrypted with your password. You can now use the file to install your certificate in your" +
|
||||
" browser or other applications.",
|
||||
}})
|
||||
|
||||
t := template.Must(template.ParseFiles("templates/index.html"))
|
||||
err := t.Execute(w, map[string]interface{}{
|
||||
"Title": csrGenTitle,
|
||||
"NameLabel": nameLabel,
|
||||
"NameHelpText": nameHelpText,
|
||||
"PasswordLabel": passwordLabel,
|
||||
"RSAKeySizeLegend": rsaKeySizeLegend,
|
||||
"RSA3072Label": rsa3072Label,
|
||||
"RSA2048Label": rsa2048Label,
|
||||
"RSA4096Label": rsa4096Label,
|
||||
"RSAHelpText": rsaHelpText,
|
||||
"CSRButtonLabel": csrButtonLabel,
|
||||
"StatusLoading": statusLoading,
|
||||
"DownloadDescription": downloadDescription,
|
||||
"DownloadLabel": downloadLabel,
|
||||
csrf.TemplateTag: csrf.TemplateField(r),
|
||||
})
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
)
|
||||
|
||||
type JSLocalesHandler struct {
|
||||
bundle *i18n.Bundle
|
||||
}
|
||||
|
||||
func NewJSLocalesHandler(bundle *i18n.Bundle) *JSLocalesHandler {
|
||||
return &JSLocalesHandler{bundle: bundle}
|
||||
}
|
||||
|
||||
func (j *JSLocalesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
parts := strings.Split(r.URL.Path, "/")
|
||||
if len(parts) != 4 {
|
||||
http.Error(w, "Not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
lang := parts[2]
|
||||
|
||||
localizer := i18n.NewLocalizer(j.bundle, lang)
|
||||
|
||||
type translationData struct {
|
||||
Keygen struct {
|
||||
Started string `json:"started"`
|
||||
Running string `json:"running"`
|
||||
Generated string `json:"generated"`
|
||||
} `json:"keygen"`
|
||||
Certificate struct {
|
||||
Waiting string `json:"waiting"`
|
||||
Received string `json:"received"`
|
||||
} `json:"certificate"`
|
||||
}
|
||||
|
||||
translations := &translationData{}
|
||||
translations.Keygen.Started = localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "JavaScript.KeyGen.Started",
|
||||
Other: "started key generation",
|
||||
}})
|
||||
translations.Keygen.Running = localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "JavaScript.KeyGen.Running",
|
||||
Other: "key generation running for __seconds__ seconds",
|
||||
}})
|
||||
translations.Keygen.Generated = localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "JavaScript.KeyGen.Generated",
|
||||
Other: "key generated in __seconds__ seconds",
|
||||
}})
|
||||
translations.Certificate.Waiting = localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "JavaScript.Certificate.Waiting",
|
||||
Other: "waiting for certificate ...",
|
||||
}})
|
||||
translations.Certificate.Received = localizer.MustLocalize(&i18n.LocalizeConfig{DefaultMessage: &i18n.Message{
|
||||
ID: "JavaScript.Certificate.Received",
|
||||
Other: "received certificate from CA",
|
||||
}})
|
||||
|
||||
encoder := json.NewEncoder(w)
|
||||
if err := encoder.Encode(translations); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
@ -1,215 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type SigningRequestRegistry struct {
|
||||
caCertificates []*x509.Certificate
|
||||
caChainMap map[string][]string
|
||||
requests map[string]chan *responseData
|
||||
}
|
||||
|
||||
func NewSigningRequestRegistry(caCertificates []*x509.Certificate) *SigningRequestRegistry {
|
||||
return &SigningRequestRegistry{
|
||||
caCertificates: caCertificates,
|
||||
caChainMap: make(map[string][]string),
|
||||
requests: make(map[string]chan *responseData),
|
||||
}
|
||||
}
|
||||
|
||||
type SigningRequestAttributes struct {
|
||||
CommonName string
|
||||
CSRBytes []byte
|
||||
RequestToken string
|
||||
}
|
||||
|
||||
func (registry *SigningRequestRegistry) AddSigningRequest(request *requestData) (string, error) {
|
||||
requestToken, csrBytes, err := validateCsr(request.Csr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
requestAttributes := &SigningRequestAttributes{
|
||||
CommonName: request.CommonName,
|
||||
CSRBytes: csrBytes,
|
||||
RequestToken: requestToken,
|
||||
}
|
||||
go func() {
|
||||
responseChannel := make(chan *responseData, 1)
|
||||
registry.requests[requestToken] = responseChannel
|
||||
registry.signCertificate(responseChannel, requestAttributes)
|
||||
}()
|
||||
return requestToken, nil
|
||||
}
|
||||
|
||||
func validateCsr(csr string) (string, []byte, error) {
|
||||
csrBlock, _ := pem.Decode([]byte(csr))
|
||||
if csrBlock == nil {
|
||||
return "", nil, errors.New("request data did not contain valid PEM data")
|
||||
}
|
||||
if csrBlock.Type != "CERTIFICATE REQUEST" {
|
||||
return "", nil, fmt.Errorf("request is not valid, type in PEM data is %s", csrBlock.Type)
|
||||
}
|
||||
var err error
|
||||
var csrContent *x509.CertificateRequest
|
||||
csrContent, err = x509.ParseCertificateRequest(csrBlock.Bytes)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if err = csrContent.CheckSignature(); err != nil {
|
||||
log.Errorf("invalid CSR signature %v", err)
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// generate request token as defined in CAB Baseline Requirements 1.7.3 Request Token definition
|
||||
requestToken := fmt.Sprintf(
|
||||
"%s%x", time.Now().UTC().Format("200601021504"), sha256.Sum256(csrContent.Raw),
|
||||
)
|
||||
log.Debugf("generated request token %s", requestToken)
|
||||
return requestToken, csrContent.Raw, nil
|
||||
}
|
||||
|
||||
func (registry *SigningRequestRegistry) signCertificate(channel chan *responseData, request *SigningRequestAttributes) {
|
||||
responseData, err := registry.sign(request)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
close(channel)
|
||||
return
|
||||
}
|
||||
channel <- responseData
|
||||
}
|
||||
|
||||
func (registry *SigningRequestRegistry) sign(request *SigningRequestAttributes) (*responseData, error) {
|
||||
log.Infof("handling signing request %s", request.RequestToken)
|
||||
subjectDN := fmt.Sprintf("/CN=%s", request.CommonName)
|
||||
|
||||
var err error
|
||||
var csrFile *os.File
|
||||
if csrFile, err = ioutil.TempFile("", "*.csr.pem"); err != nil {
|
||||
log.Errorf("could not open temporary file: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
if err = pem.Encode(csrFile, &pem.Block{
|
||||
Type: "CERTIFICATE REQUEST",
|
||||
Bytes: request.CSRBytes,
|
||||
}); err != nil {
|
||||
log.Errorf("could not write CSR to file: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
if err = csrFile.Close(); err != nil {
|
||||
log.Errorf("could not close CSR file: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err = os.Remove(file.Name())
|
||||
if err != nil {
|
||||
log.Errorf("could not remove temporary file: %s", err)
|
||||
}
|
||||
}(csrFile)
|
||||
|
||||
// simulate a delay during certificate creation
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
opensslCommand := exec.Command(
|
||||
"openssl", "ca", "-config", "ca.cnf", "-name", "email_ca",
|
||||
"-policy", "policy_match", "-extensions", "email_ext",
|
||||
"-batch", "-subj", subjectDN, "-utf8", "-rand_serial", "-in", csrFile.Name())
|
||||
var out, cmdErr bytes.Buffer
|
||||
opensslCommand.Stdout = &out
|
||||
opensslCommand.Stderr = &cmdErr
|
||||
err = opensslCommand.Run()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
log.Error(cmdErr.String())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var block *pem.Block
|
||||
if block, _ = pem.Decode(out.Bytes()); block == nil {
|
||||
err = fmt.Errorf("could not decode pem")
|
||||
return nil, err
|
||||
}
|
||||
var certificate *x509.Certificate
|
||||
if certificate, err = x509.ParseCertificate(block.Bytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var caChain []string
|
||||
if caChain, err = registry.getCAChain(certificate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := &responseData{
|
||||
Certificate: string(pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: certificate.Raw,
|
||||
})),
|
||||
CAChain: caChain,
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (registry *SigningRequestRegistry) GetResponseChannel(requestUuid string) (chan *responseData, error) {
|
||||
if responseChannel, exists := registry.requests[requestUuid]; exists {
|
||||
delete(registry.requests, requestUuid)
|
||||
return responseChannel, nil
|
||||
} else {
|
||||
return nil, errors.New("no request found")
|
||||
}
|
||||
}
|
||||
|
||||
func (registry *SigningRequestRegistry) getCAChain(certificate *x509.Certificate) ([]string, error) {
|
||||
issuerString := string(certificate.RawIssuer)
|
||||
|
||||
if value, exists := registry.caChainMap[issuerString]; exists {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
result := make([]string, 0)
|
||||
|
||||
appendCert := func(cert *x509.Certificate) {
|
||||
result = append(
|
||||
result,
|
||||
string(pem.EncodeToMemory(&pem.Block{Bytes: cert.Raw, Type: "CERTIFICATE"})))
|
||||
log.Debugf("added %s to cachain", result[len(result)-1])
|
||||
}
|
||||
|
||||
var previous *x509.Certificate
|
||||
var count = 0
|
||||
for {
|
||||
if len(registry.caCertificates) == 0 {
|
||||
return nil, errors.New("no CA certificates loaded")
|
||||
}
|
||||
if count > len(registry.caCertificates) {
|
||||
return nil, errors.New("could not construct certificate chain")
|
||||
}
|
||||
for _, caCert := range registry.caCertificates {
|
||||
if previous == nil {
|
||||
if bytes.Equal(caCert.RawSubject, certificate.RawIssuer) {
|
||||
previous = caCert
|
||||
appendCert(caCert)
|
||||
}
|
||||
} else if bytes.Equal(previous.RawSubject, previous.RawIssuer) {
|
||||
registry.caChainMap[issuerString] = result
|
||||
return result, nil
|
||||
} else if bytes.Equal(caCert.RawSubject, previous.RawIssuer) {
|
||||
previous = caCert
|
||||
appendCert(caCert)
|
||||
} else {
|
||||
log.Debugf("skipped certificate %s", caCert.Subject)
|
||||
}
|
||||
}
|
||||
count++
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type CertificateSigningHandler struct {
|
||||
requestRegistry *SigningRequestRegistry
|
||||
}
|
||||
|
||||
func NewCertificateSigningHandler(requestRegistry *SigningRequestRegistry) *CertificateSigningHandler {
|
||||
return &CertificateSigningHandler{requestRegistry: requestRegistry}
|
||||
}
|
||||
|
||||
func (h *CertificateSigningHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
http.Error(w, "Only POST requests support", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
if r.Header.Get("content-type") != "application/json" {
|
||||
http.Error(w, "Only JSON content is accepted", http.StatusNotAcceptable)
|
||||
return
|
||||
}
|
||||
var err error
|
||||
var requestBody requestData
|
||||
|
||||
if err = json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
|
||||
log.Error(err)
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
type acceptedResponse struct {
|
||||
RequestId string `json:"request_id"`
|
||||
}
|
||||
|
||||
taskUuid, err := h.requestRegistry.AddSigningRequest(&requestBody)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
response := &acceptedResponse{RequestId: taskUuid}
|
||||
if err = json.NewEncoder(w).Encode(response); err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
}
|
||||
|
||||
type requestData struct {
|
||||
Csr string `json:"csr"`
|
||||
CommonName string `json:"common_name"`
|
||||
}
|
||||
|
||||
type responseData struct {
|
||||
Certificate string `json:"certificate"`
|
||||
CAChain []string `json:"ca_chain"`
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/gobwas/ws"
|
||||
"github.com/gobwas/ws/wsutil"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type WebSocketHandler struct {
|
||||
requestRegistry *SigningRequestRegistry
|
||||
}
|
||||
|
||||
func NewWebSocketHandler(registry *SigningRequestRegistry) *WebSocketHandler {
|
||||
return &WebSocketHandler{requestRegistry: registry}
|
||||
}
|
||||
|
||||
func (w *WebSocketHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
conn, _, _, err := ws.UpgradeHTTP(request, writer)
|
||||
if err != nil {
|
||||
http.Error(writer, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer func() { _ = conn.Close() }()
|
||||
|
||||
var (
|
||||
reader = wsutil.NewReader(conn, ws.StateServerSide)
|
||||
writer = wsutil.NewWriter(conn, ws.StateServerSide, ws.OpText)
|
||||
jsonDecoder = json.NewDecoder(reader)
|
||||
jsonEncoder = json.NewEncoder(writer)
|
||||
)
|
||||
|
||||
for {
|
||||
header, err := reader.NextFrame()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
break
|
||||
}
|
||||
if header.OpCode == ws.OpClose {
|
||||
log.Debug("channel closed")
|
||||
break
|
||||
}
|
||||
|
||||
type requestType struct {
|
||||
RequestId string `json:"request_id"`
|
||||
}
|
||||
|
||||
request := &requestType{}
|
||||
err = jsonDecoder.Decode(request)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
break
|
||||
}
|
||||
|
||||
channel, err := w.requestRegistry.GetResponseChannel(request.RequestId)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
break
|
||||
}
|
||||
|
||||
var response *responseData
|
||||
response = <-channel
|
||||
if err = jsonEncoder.Encode(response); err != nil {
|
||||
log.Error(err)
|
||||
break
|
||||
}
|
||||
close(channel)
|
||||
|
||||
if err = writer.Flush(); err != nil {
|
||||
log.Error(err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/gorilla/csrf"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"code.cacert.org/jandd/poc-browser-csr-generation/handlers"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFormatter(&log.TextFormatter{
|
||||
FullTimestamp: true,
|
||||
})
|
||||
|
||||
bundle := loadI18nBundle()
|
||||
mux := http.NewServeMux()
|
||||
|
||||
csrfKey := initCSRFKey()
|
||||
|
||||
signingRequestRegistry := handlers.NewSigningRequestRegistry(loadCACertificates())
|
||||
mux.Handle("/sign/", handlers.NewCertificateSigningHandler(signingRequestRegistry))
|
||||
mux.Handle("/", handlers.NewIndexHandler(bundle))
|
||||
fileServer := http.FileServer(http.Dir("./public"))
|
||||
mux.Handle("/css/", fileServer)
|
||||
mux.Handle("/js/", fileServer)
|
||||
mux.Handle("/locales/", handlers.NewJSLocalesHandler(bundle))
|
||||
mux.Handle("/ws/", handlers.NewWebSocketHandler(signingRequestRegistry))
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
CipherSuites: []uint16{
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
},
|
||||
NextProtos: []string{"h2"},
|
||||
PreferServerCipherSuites: true,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}
|
||||
server := http.Server{
|
||||
Addr: ":8000",
|
||||
Handler: csrf.Protect(csrfKey, csrf.FieldName("csrfToken"), csrf.RequestHeader("X-CSRF-Token"))(mux),
|
||||
TLSConfig: tlsConfig,
|
||||
ReadTimeout: 20 * time.Second,
|
||||
ReadHeaderTimeout: 5 * time.Second,
|
||||
WriteTimeout: 30 * time.Second,
|
||||
IdleTimeout: 30 * time.Second,
|
||||
}
|
||||
go func() {
|
||||
err := server.ListenAndServeTLS("server.crt.pem", "server.key.pem")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
var hostPort string
|
||||
if strings.HasPrefix(server.Addr, ":") {
|
||||
hostPort = fmt.Sprintf("localhost%s", server.Addr)
|
||||
} else {
|
||||
hostPort = server.Addr
|
||||
}
|
||||
log.Infof("started web server on https://%s/", hostPort)
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
s := <-c
|
||||
log.Infof("received %s, shutting down", s)
|
||||
_ = server.Close()
|
||||
}
|
||||
|
||||
func loadI18nBundle() *i18n.Bundle {
|
||||
bundle := i18n.NewBundle(language.English)
|
||||
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
|
||||
for _, lang := range []string{"en-US", "de-DE"} {
|
||||
if _, err := bundle.LoadMessageFile(fmt.Sprintf("active.%s.toml", lang)); err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
return bundle
|
||||
}
|
||||
|
||||
func initCSRFKey() []byte {
|
||||
var csrfKey []byte = nil
|
||||
|
||||
if csrfB64, exists := os.LookupEnv("CSRF_KEY"); exists {
|
||||
csrfKey, _ = base64.RawStdEncoding.DecodeString(csrfB64)
|
||||
log.Info("read CSRF key from environment variable")
|
||||
}
|
||||
if csrfKey == nil {
|
||||
csrfKey = generateRandomBytes(32)
|
||||
log.Infof(
|
||||
"generated new random CSRF key, set environment variable CSRF_KEY to %s to "+
|
||||
"keep the same key for new sessions",
|
||||
base64.RawStdEncoding.EncodeToString(csrfKey))
|
||||
}
|
||||
return csrfKey
|
||||
}
|
||||
|
||||
func generateRandomBytes(count int) []byte {
|
||||
randomBytes := make([]byte, count)
|
||||
|
||||
_, err := rand.Read(randomBytes)
|
||||
if err != nil {
|
||||
log.Fatalf("could not read random bytes: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return randomBytes
|
||||
}
|
||||
|
||||
func loadCACertificates() (caCertificates []*x509.Certificate) {
|
||||
var err error
|
||||
caFiles, err := filepath.Glob("example_ca/*/ca.crt.pem")
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
caCertificates = make([]*x509.Certificate, len(caFiles))
|
||||
for index, certFile := range caFiles {
|
||||
var certBytes []byte
|
||||
if certBytes, err = ioutil.ReadFile(certFile); err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
var block *pem.Block
|
||||
if block, _ = pem.Decode(certBytes); block == nil {
|
||||
log.Panicf("no PEM data found in %s", certFile)
|
||||
return
|
||||
}
|
||||
if caCertificates[index], err = x509.ParseCertificate(block.Bytes); err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
log.Infof("read %d CA certificates", len(caCertificates))
|
||||
return
|
||||
}
|
@ -1,615 +0,0 @@
|
||||
-- +goose Up
|
||||
|
||||
-- LibreSSL - CAcert web application
|
||||
-- Copyright (C) 2004-2020 CAcert Inc.
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; version 2 of the License.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program; if not, write to the Free Software
|
||||
-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-- Initial database schema
|
||||
CREATE TABLE `abusereports` (
|
||||
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`when` datetime NOT NULL,
|
||||
`IP` int(11) DEFAULT NULL,
|
||||
`url` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`email` varchar(255) NOT NULL,
|
||||
`comment` varchar(255) NOT NULL,
|
||||
`reason` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `addlang` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`userid` int(11) NOT NULL,
|
||||
`lang` varchar(5) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `userid` (`userid`, `lang`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `adminlog` (
|
||||
`when` datetime NOT NULL,
|
||||
`uid` int(11) NOT NULL,
|
||||
`adminid` int(11) NOT NULL,
|
||||
`actiontypeid` int(11) DEFAULT NULL,
|
||||
`old-lname` varchar(255),
|
||||
`old-dob` varchar(255),
|
||||
`new-lname` varchar(255),
|
||||
`new-dob` varchar(255)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `advertising` (
|
||||
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`replaceid` int(10) UNSIGNED NOT NULL,
|
||||
`replaced` tinyint(3) UNSIGNED NOT NULL,
|
||||
`orderid` tinyint(3) UNSIGNED NOT NULL,
|
||||
`link` varchar(255) NOT NULL,
|
||||
`title` varchar(255) NOT NULL,
|
||||
`months` tinyint(3) UNSIGNED NOT NULL,
|
||||
`who` int(10) UNSIGNED NOT NULL,
|
||||
`when` datetime NOT NULL,
|
||||
`active` tinyint(3) UNSIGNED NOT NULL,
|
||||
`approvedby` int(10) UNSIGNED NOT NULL,
|
||||
`expires` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `alerts` (
|
||||
`memid` int(11) NOT NULL DEFAULT 0,
|
||||
`general` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`country` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`regional` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`radius` tinyint(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`memid`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `baddomains` (
|
||||
`domain` varchar(255) NOT NULL DEFAULT ''
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `cats_passed` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL,
|
||||
`variant_id` int(11) NOT NULL,
|
||||
`pass_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP(),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `test_passed` (`user_id`, `variant_id`, `pass_date`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `cats_type` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`type_text` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `type_text` (`type_text`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `cats_variant` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`type_id` int(11) NOT NULL,
|
||||
`test_text` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `test_text` (`test_text`, `type_id`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `countries` (
|
||||
`id` int(3) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(50) NOT NULL DEFAULT '',
|
||||
`acount` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `disputedomain` (
|
||||
`id` int(11) NOT NULL DEFAULT 0,
|
||||
`memid` int(11) NOT NULL DEFAULT 0,
|
||||
`oldmemid` int(11) NOT NULL DEFAULT 0,
|
||||
`domain` varchar(255) NOT NULL DEFAULT '',
|
||||
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`hash` varchar(50) NOT NULL DEFAULT '',
|
||||
`attempts` int(1) NOT NULL DEFAULT 0,
|
||||
`action` enum ('accept','reject','failed') NOT NULL DEFAULT 'accept'
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `disputeemail` (
|
||||
`id` int(11) NOT NULL DEFAULT 0,
|
||||
`memid` int(11) NOT NULL DEFAULT 0,
|
||||
`oldmemid` int(11) NOT NULL DEFAULT 0,
|
||||
`email` varchar(255) NOT NULL DEFAULT '',
|
||||
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`hash` varchar(50) NOT NULL DEFAULT '',
|
||||
`attempts` int(1) NOT NULL DEFAULT 0,
|
||||
`action` enum ('accept','reject','failed') NOT NULL DEFAULT 'accept',
|
||||
`IP` varchar(20) NOT NULL DEFAULT ''
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `domaincerts` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`domid` int(11) NOT NULL DEFAULT 0,
|
||||
`serial` varchar(50) NOT NULL DEFAULT '',
|
||||
`CN` varchar(255) NOT NULL DEFAULT '',
|
||||
`subject` text NOT NULL,
|
||||
`csr_name` varchar(255) NOT NULL DEFAULT '',
|
||||
`crt_name` varchar(255) NOT NULL DEFAULT '',
|
||||
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`revoked` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`expire` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`warning` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`renewed` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`rootcert` int(2) NOT NULL DEFAULT 1,
|
||||
`md` enum ('md5','sha1','sha256','sha512') NOT NULL DEFAULT 'sha512',
|
||||
`type` tinyint(4) DEFAULT NULL,
|
||||
`pkhash` char(40) DEFAULT NULL,
|
||||
`certhash` char(40) DEFAULT NULL,
|
||||
`coll_found` tinyint(1) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `domaincerts_pkhash` (`pkhash`),
|
||||
KEY `revoked` (`revoked`),
|
||||
KEY `created` (`created`),
|
||||
KEY `domid` (`domid`),
|
||||
KEY `serial` (`serial`),
|
||||
KEY `stats_domaincerts_expire` (`expire`),
|
||||
KEY `domaincrt` (`crt_name`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `domains` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`memid` int(11) NOT NULL DEFAULT 0,
|
||||
`domain` varchar(255) NOT NULL DEFAULT '',
|
||||
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`deleted` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`hash` varchar(50) NOT NULL DEFAULT '',
|
||||
`attempts` int(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `memid` (`memid`),
|
||||
KEY `domain` (`domain`),
|
||||
KEY `memid_2` (`memid`),
|
||||
KEY `stats_domains_hash` (`hash`),
|
||||
KEY `stats_domains_deleted` (`deleted`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `domlink` (
|
||||
`certid` int(11) NOT NULL DEFAULT 0,
|
||||
`domid` int(11) NOT NULL DEFAULT 0,
|
||||
UNIQUE KEY `index` (`certid`, `domid`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `email` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`memid` int(11) NOT NULL DEFAULT 0,
|
||||
`email` varchar(255) NOT NULL DEFAULT '',
|
||||
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`deleted` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`hash` varchar(50) NOT NULL DEFAULT '',
|
||||
`attempts` int(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `memid` (`memid`),
|
||||
KEY `stats_email_hash` (`hash`),
|
||||
KEY `stats_email_deleted` (`deleted`),
|
||||
KEY `email` (`email`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `emailcerts` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`memid` int(11) NOT NULL DEFAULT 0,
|
||||
`serial` varchar(50) NOT NULL DEFAULT '',
|
||||
`CN` varchar(255) NOT NULL DEFAULT '',
|
||||
`subject` text NOT NULL,
|
||||
`keytype` char(2) NOT NULL DEFAULT 'NS',
|
||||
`codesign` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`csr_name` varchar(255) NOT NULL DEFAULT '',
|
||||
`crt_name` varchar(255) NOT NULL DEFAULT '',
|
||||
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`revoked` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`expire` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`warning` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`renewed` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`rootcert` int(2) NOT NULL DEFAULT 1,
|
||||
`md` enum ('md5','sha1','sha256','sha512') NOT NULL DEFAULT 'sha512',
|
||||
`type` tinyint(4) DEFAULT NULL,
|
||||
`disablelogin` int(1) NOT NULL DEFAULT 0,
|
||||
`pkhash` char(40) DEFAULT NULL,
|
||||
`certhash` char(40) DEFAULT NULL,
|
||||
`coll_found` tinyint(1) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `emailcerts_pkhash` (`pkhash`),
|
||||
KEY `revoked` (`revoked`),
|
||||
KEY `created` (`created`),
|
||||
KEY `memid` (`memid`),
|
||||
KEY `serial` (`serial`),
|
||||
KEY `stats_emailcerts_expire` (`expire`),
|
||||
KEY `emailcrt` (`crt_name`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `emaillink` (
|
||||
`emailcertsid` int(11) NOT NULL DEFAULT 0,
|
||||
`emailid` int(11) NOT NULL DEFAULT 0,
|
||||
KEY `index` (`emailcertsid`, `emailid`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `gpg` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`memid` int(11) NOT NULL DEFAULT 0,
|
||||
`email` varchar(255) NOT NULL DEFAULT '',
|
||||
`level` int(1) NOT NULL DEFAULT 0,
|
||||
`multiple` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`expires` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`csr` varchar(255) NOT NULL DEFAULT '',
|
||||
`crt` varchar(255) NOT NULL DEFAULT '',
|
||||
`issued` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`expire` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`keyid` char(18) DEFAULT NULL,
|
||||
`warning` tinyint(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `stats_gpg_expire` (`expire`),
|
||||
KEY `stats_gpg_issued` (`issued`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `languages` (
|
||||
`locale` varchar(5) NOT NULL,
|
||||
`en_co` varchar(255) NOT NULL,
|
||||
`en_lang` varchar(255) NOT NULL,
|
||||
`country` varchar(255) NOT NULL,
|
||||
`lang` varchar(255) NOT NULL
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `localias` (
|
||||
`locid` int(11) NOT NULL DEFAULT 0,
|
||||
`name` varchar(255) NOT NULL DEFAULT '',
|
||||
KEY `locid` (`locid`),
|
||||
KEY `name` (`name`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `locations` (
|
||||
`id` int(7) NOT NULL AUTO_INCREMENT,
|
||||
`regid` int(4) NOT NULL DEFAULT 0,
|
||||
`ccid` int(3) NOT NULL DEFAULT 0,
|
||||
`name` varchar(50) NOT NULL DEFAULT '',
|
||||
`lat` double(6, 3) NOT NULL DEFAULT 0.000,
|
||||
`long` double(6, 3) NOT NULL DEFAULT 0.000,
|
||||
`acount` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `ccid` (`ccid`),
|
||||
KEY `regid` (`regid`),
|
||||
KEY `name` (`name`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `news` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`when` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`who` varchar(255) NOT NULL DEFAULT '',
|
||||
`short` varchar(255) NOT NULL DEFAULT '',
|
||||
`story` text NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = latin1;
|
||||
|
||||
CREATE TABLE `notary` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`from` int(11) NOT NULL DEFAULT 0,
|
||||
`to` int(11) NOT NULL DEFAULT 0,
|
||||
`awarded` int(3) NOT NULL DEFAULT 0,
|
||||
`points` int(3) NOT NULL DEFAULT 0,
|
||||
`method` enum ('Face to Face Meeting','Trusted Third Parties','Thawte Points Transfer','Administrative Increase','CT Magazine - Germany','Temporary Increase','Unknown') NOT NULL DEFAULT 'Face to Face Meeting',
|
||||
`location` varchar(255) NOT NULL DEFAULT '',
|
||||
`date` varchar(255) NOT NULL DEFAULT '',
|
||||
`when` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`expire` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`sponsor` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `from` (`from`),
|
||||
KEY `to` (`to`),
|
||||
KEY `from_2` (`from`),
|
||||
KEY `to_2` (`to`),
|
||||
KEY `stats_notary_when` (`when`),
|
||||