Added openapi description
This commit is contained in:
parent
37a1a98c49
commit
251beb24d3
2
app.go
2
app.go
|
@ -173,7 +173,7 @@ func run(args options) {
|
|||
for { // this is an endless loop
|
||||
httpsServer.cond.L.Lock()
|
||||
// this mechanism doesn't let us through until all conditions are ment
|
||||
for config.TLS.Enabled == false || config.TLS.PortHTTPS == 0 || config.TLS.PrivateKey == "" || config.TLS.CertificateChain == "" { // sleep until neccessary data is supplied
|
||||
for config.TLS.Enabled == false || config.TLS.PortHTTPS == 0 || config.TLS.PrivateKey == "" || config.TLS.CertificateChain == "" { // sleep until necessary data is supplied
|
||||
httpsServer.cond.Wait()
|
||||
}
|
||||
address := net.JoinHostPort(config.BindHost, strconv.Itoa(config.TLS.PortHTTPS))
|
||||
|
|
33
config.go
33
config.go
|
@ -63,37 +63,34 @@ type dnsConfig struct {
|
|||
var defaultDNS = []string{"tls://1.1.1.1", "tls://1.0.0.1"}
|
||||
|
||||
type tlsConfigSettings struct {
|
||||
Enabled bool `yaml:"enabled" json:"enabled"`
|
||||
ServerName string `yaml:"server_name" json:"server_name,omitempty"`
|
||||
ForceHTTPS bool `yaml:"force_https" json:"force_https,omitempty"`
|
||||
PortHTTPS int `yaml:"port_https" json:"port_https,omitempty"`
|
||||
PortDNSOverTLS int `yaml:"port_dns_over_tls" json:"port_dns_over_tls,omitempty"`
|
||||
Enabled bool `yaml:"enabled" json:"enabled"` // Enabled is the encryption (DOT/DOH/HTTPS) status
|
||||
ServerName string `yaml:"server_name" json:"server_name,omitempty"` // ServerName is the hostname of your HTTPS/TLS server
|
||||
ForceHTTPS bool `yaml:"force_https" json:"force_https,omitempty"` // ForceHTTPS: if true, forces HTTP->HTTPS redirect
|
||||
PortHTTPS int `yaml:"port_https" json:"port_https,omitempty"` // HTTPS port. If 0, HTTPS will be disabled
|
||||
PortDNSOverTLS int `yaml:"port_dns_over_tls" json:"port_dns_over_tls,omitempty"` // DNS-over-TLS port. If 0, DOT will be disabled
|
||||
|
||||
dnsforward.TLSConfig `yaml:",inline" json:",inline"`
|
||||
}
|
||||
|
||||
// field ordering is not important -- these are for API and are recalculated on each run
|
||||
type tlsConfigStatus struct {
|
||||
// certificate status
|
||||
ValidCert bool `yaml:"-" json:"valid_cert"`
|
||||
ValidChain bool `yaml:"-" json:"valid_chain"`
|
||||
Subject string `yaml:"-" json:"subject,omitempty"`
|
||||
Issuer string `yaml:"-" json:"issuer,omitempty"`
|
||||
NotBefore time.Time `yaml:"-" json:"not_before,omitempty"`
|
||||
NotAfter time.Time `yaml:"-" json:"not_after,omitempty"`
|
||||
DNSNames []string `yaml:"-" json:"dns_names"`
|
||||
StatusCertificate string `yaml:"-" json:"status_cert,omitempty"`
|
||||
ValidCert bool `yaml:"-" json:"valid_cert"` // ValidCert is true if the specified certificates chain is a valid chain of X509 certificates
|
||||
ValidChain bool `yaml:"-" json:"valid_chain"` // ValidChain is true if the specified certificates chain is verified and issued by a known CA
|
||||
Subject string `yaml:"-" json:"subject,omitempty"` // Subject is the subject of the first certificate in the chain
|
||||
Issuer string `yaml:"-" json:"issuer,omitempty"` // Issuer is the issuer of the first certificate in the chain
|
||||
NotBefore time.Time `yaml:"-" json:"not_before,omitempty"` // NotBefore is the NotBefore field of the first certificate in the chain
|
||||
NotAfter time.Time `yaml:"-" json:"not_after,omitempty"` // NotAfter is the NotAfter field of the first certificate in the chain
|
||||
DNSNames []string `yaml:"-" json:"dns_names"` // DNSNames is the value of SubjectAltNames field of the first certificate in the chain
|
||||
|
||||
// key status
|
||||
ValidKey bool `yaml:"-" json:"valid_key"`
|
||||
KeyType string `yaml:"-" json:"key_type,omitempty"`
|
||||
ValidKey bool `yaml:"-" json:"valid_key"` // ValidKey is true if the key is a valid private key
|
||||
KeyType string `yaml:"-" json:"key_type,omitempty"` // KeyType is one of RSA or ECDSA
|
||||
|
||||
// is usable? set by validator
|
||||
usable bool
|
||||
|
||||
// warnings
|
||||
Warning string `yaml:"-" json:"warning,omitempty"`
|
||||
WarningValidation string `yaml:"-" json:"warning_validation,omitempty"`
|
||||
WarningValidation string `yaml:"-" json:"warning_validation,omitempty"` // WarningValidation is a validation warning message with the issue description
|
||||
}
|
||||
|
||||
// field ordering is important -- yaml fields will mirror ordering from here
|
||||
|
|
24
control.go
24
control.go
|
@ -1118,7 +1118,7 @@ func validateCertificates(data tlsConfig) tlsConfig {
|
|||
// clear out status for certificates
|
||||
data.tlsConfigStatus = tlsConfigStatus{}
|
||||
|
||||
// check only public certificate separetely from the key
|
||||
// check only public certificate separately from the key
|
||||
if data.CertificateChain != "" {
|
||||
log.Tracef("got certificate: %s", data.CertificateChain)
|
||||
|
||||
|
@ -1194,24 +1194,6 @@ func validateCertificates(data tlsConfig) tlsConfig {
|
|||
data.NotAfter = notAfter
|
||||
data.NotBefore = mainCert.NotBefore
|
||||
data.DNSNames = mainCert.DNSNames
|
||||
|
||||
data.StatusCertificate = fmt.Sprintf("Certificate expires on %s", notAfter) //, valid for hostname %s", mainCert.NotAfter, mainCert.Subject.CommonName)
|
||||
if len(mainCert.DNSNames) == 1 {
|
||||
data.StatusCertificate += fmt.Sprintf(", valid for hostname %s", mainCert.DNSNames[0])
|
||||
} else if len(mainCert.DNSNames) > 1 {
|
||||
data.StatusCertificate += ", valid for hostnames " + strings.Join(mainCert.DNSNames, ", ")
|
||||
}
|
||||
|
||||
// issue a warning if certificate is about to expire
|
||||
now := time.Now()
|
||||
if now.AddDate(0, 0, 30).After(notAfter) {
|
||||
timeLeft := notAfter.Sub(now)
|
||||
if timeLeft > 0 {
|
||||
data.Warning = fmt.Sprintf("Your certificate expires in %.0f days, we recommend you update it soon", timeLeft.Hours()/24)
|
||||
} else {
|
||||
data.Warning = fmt.Sprintf("Your certificate has expired on %s, we recommend you update it immediatedly", mainCert.NotAfter)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1322,11 +1304,11 @@ func marshalTLS(w http.ResponseWriter, data tlsConfig) {
|
|||
w.Header().Set("Content-Type", "application/json")
|
||||
if data.CertificateChain != "" {
|
||||
encoded := base64.StdEncoding.EncodeToString([]byte(data.CertificateChain))
|
||||
data.CertificateChain = string(encoded)
|
||||
data.CertificateChain = encoded
|
||||
}
|
||||
if data.PrivateKey != "" {
|
||||
encoded := base64.StdEncoding.EncodeToString([]byte(data.PrivateKey))
|
||||
data.PrivateKey = string(encoded)
|
||||
data.PrivateKey = encoded
|
||||
}
|
||||
err := json.NewEncoder(w).Encode(data)
|
||||
if err != nil {
|
||||
|
|
29
helpers.go
29
helpers.go
|
@ -6,7 +6,6 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -257,34 +256,6 @@ func checkPacketPortAvailable(host string, port int) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// ------------------------
|
||||
// random string generation
|
||||
// ------------------------
|
||||
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
const (
|
||||
letterIdxBits = 6 // 6 bits to represent a letter index
|
||||
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
||||
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
||||
)
|
||||
|
||||
func RandStringBytesMaskImpr(n int) string {
|
||||
b := make([]byte, n)
|
||||
// A rand.Int63() generates 63 random bits, enough for letterIdxMax letters!
|
||||
for i, cache, remain := n-1, rand.Int63(), letterIdxMax; i >= 0; {
|
||||
if remain == 0 {
|
||||
cache, remain = rand.Int63(), letterIdxMax
|
||||
}
|
||||
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
||||
b[i] = letterBytes[idx]
|
||||
i--
|
||||
}
|
||||
cache >>= letterIdxBits
|
||||
remain--
|
||||
}
|
||||
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
// debug logging helpers
|
||||
// ---------------------
|
||||
|
|
|
@ -2,7 +2,7 @@ swagger: '2.0'
|
|||
info:
|
||||
title: 'AdGuard Home'
|
||||
description: 'AdGuard Home REST API. Admin web interface is built on top of this REST API.'
|
||||
version: 0.92.0
|
||||
version: 0.93.0
|
||||
schemes:
|
||||
- http
|
||||
basePath: /control
|
||||
|
@ -12,6 +12,9 @@ tags:
|
|||
-
|
||||
name: global
|
||||
description: 'AdGuard Home server general settings and controls'
|
||||
-
|
||||
name: tls
|
||||
description: 'AdGuard Home HTTPS/DOH/DOT settings'
|
||||
-
|
||||
name: log
|
||||
description: 'AdGuard Home query log'
|
||||
|
@ -267,6 +270,70 @@ paths:
|
|||
200:
|
||||
description: OK
|
||||
|
||||
# --------------------------------------------------
|
||||
# TLS server methods
|
||||
# --------------------------------------------------
|
||||
|
||||
/tls/status:
|
||||
get:
|
||||
tags:
|
||||
- tls
|
||||
operationId: tlsStatus
|
||||
summary: "Returns TLS configuration and its status"
|
||||
responses:
|
||||
200:
|
||||
description: OK
|
||||
schema:
|
||||
$ref: "#/definitions/TlsConfig"
|
||||
|
||||
/tls/configure:
|
||||
post:
|
||||
tags:
|
||||
- tls
|
||||
operationId: tlsConfigure
|
||||
summary: "Updates current TLS configuration"
|
||||
consumes:
|
||||
- application/json
|
||||
parameters:
|
||||
- in: "body"
|
||||
name: "body"
|
||||
description: "TLS configuration JSON"
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/TlsConfig"
|
||||
responses:
|
||||
200:
|
||||
description: "TLS configuration and its status"
|
||||
schema:
|
||||
$ref: "#/definitions/TlsConfig"
|
||||
400:
|
||||
description: "Invalid configuration or unavailable port"
|
||||
500:
|
||||
description: "Error occurred while applying configuration"
|
||||
|
||||
/tls/validate:
|
||||
post:
|
||||
tags:
|
||||
- tls
|
||||
operationId: tlsValidate
|
||||
summary: "Checks if the current TLS configuration is valid"
|
||||
consumes:
|
||||
- application/json
|
||||
parameters:
|
||||
- in: "body"
|
||||
name: "body"
|
||||
description: "TLS configuration JSON"
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/TlsConfig"
|
||||
responses:
|
||||
200:
|
||||
description: "TLS configuration and its status"
|
||||
schema:
|
||||
$ref: "#/definitions/TlsConfig"
|
||||
400:
|
||||
description: "Invalid configuration or unavailable port"
|
||||
|
||||
# --------------------------------------------------
|
||||
# DHCP server methods
|
||||
# --------------------------------------------------
|
||||
|
@ -1063,4 +1130,81 @@ definitions:
|
|||
type: "array"
|
||||
description: "Query log"
|
||||
items:
|
||||
$ref: "#/definitions/QueryLogItem"
|
||||
$ref: "#/definitions/QueryLogItem"
|
||||
TlsConfig:
|
||||
type: "object"
|
||||
description: "TLS configuration settings and status"
|
||||
properties:
|
||||
# TLS configuration
|
||||
enabled:
|
||||
type: "boolean"
|
||||
example: "true"
|
||||
description: "enabled is the encryption (DOT/DOH/HTTPS) status"
|
||||
server_name:
|
||||
type: "string"
|
||||
example: "example.org"
|
||||
description: "server_name is the hostname of your HTTPS/TLS server"
|
||||
force_https:
|
||||
type: "boolean"
|
||||
example: "true"
|
||||
description: "if true, forces HTTP->HTTPS redirect"
|
||||
port_https:
|
||||
type: "integer"
|
||||
format: "int32"
|
||||
example: 443
|
||||
description: "HTTPS port. If 0, HTTPS will be disabled."
|
||||
port_dns_over_tls:
|
||||
type: "integer"
|
||||
format: "int32"
|
||||
example: 853
|
||||
description: "DNS-over-TLS port. If 0, DOT will be disabled."
|
||||
certificate_chain:
|
||||
type: "string"
|
||||
description: "Base64 string with PEM-encoded certificates chain"
|
||||
private_key:
|
||||
type: "string"
|
||||
description: "Base64 string with PEM-encoded private key"
|
||||
# Below goes validation fields
|
||||
valid_cert:
|
||||
type: "boolean"
|
||||
example: "true"
|
||||
description: "valid_cert is true if the specified certificates chain is a valid chain of X509 certificates"
|
||||
valid_chain:
|
||||
type: "boolean"
|
||||
example: "true"
|
||||
description: "valid_chain is true if the specified certificates chain is verified and issued by a known CA"
|
||||
subject:
|
||||
type: "string"
|
||||
example: "CN=example.org"
|
||||
description: "subject is the subject of the first certificate in the chain"
|
||||
issuer:
|
||||
type: "string"
|
||||
example: "CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US"
|
||||
description: "issuer is the issuer of the first certificate in the chain"
|
||||
not_before:
|
||||
type: "string"
|
||||
example: "2019-01-31T10:47:32Z"
|
||||
description: "not_before is the NotBefore field of the first certificate in the chain"
|
||||
not_after:
|
||||
type: "string"
|
||||
example: "2019-05-01T10:47:32Z"
|
||||
description: "not_after is the NotAfter field of the first certificate in the chain"
|
||||
dns_names:
|
||||
type: "array"
|
||||
items:
|
||||
type: "string"
|
||||
description: "dns_names is the value of SubjectAltNames field of the first certificate in the chain"
|
||||
example:
|
||||
- "*.example.org"
|
||||
valid_key:
|
||||
type: "boolean"
|
||||
example: "true"
|
||||
description: "valid_key is true if the key is a valid private key"
|
||||
key_type:
|
||||
type: "string"
|
||||
example: "RSA"
|
||||
description: "key_type is either RSA or ECDSA"
|
||||
warning_validation:
|
||||
type: "string"
|
||||
example: "You have specified an empty certificate"
|
||||
description: "warning_validation is a validation warning message with the issue description"
|
Loading…
Reference in New Issue