[server] Add initial HTTP/2 and TLS support by using net.http
This commit is contained in:
parent
ad089651b1
commit
a1e456d290
2 changed files with 263 additions and 33 deletions
|
@ -3,7 +3,9 @@
|
|||
package server
|
||||
|
||||
|
||||
import "bufio"
|
||||
import "bytes"
|
||||
import "crypto/tls"
|
||||
import "flag"
|
||||
import "fmt"
|
||||
import "io"
|
||||
|
@ -34,6 +36,7 @@ import . "github.com/volution/kawipiko/lib/server"
|
|||
|
||||
type server struct {
|
||||
httpServer *fasthttp.Server
|
||||
httpsServer *http.Server
|
||||
cdbReader *cdb.CDB
|
||||
cachedFileFingerprints map[string][]byte
|
||||
cachedDataMeta map[string][]byte
|
||||
|
@ -41,6 +44,7 @@ type server struct {
|
|||
securityHeadersEnabled bool
|
||||
securityHeadersTls bool
|
||||
debug bool
|
||||
quiet bool
|
||||
dummy bool
|
||||
}
|
||||
|
||||
|
@ -49,6 +53,11 @@ type server struct {
|
|||
|
||||
func (_server *server) Serve (_context *fasthttp.RequestCtx) () {
|
||||
|
||||
if _server.dummy {
|
||||
_server.ServeDummy (_context)
|
||||
return
|
||||
}
|
||||
|
||||
// _request := (*fasthttp.Request) (NoEscape (unsafe.Pointer (&_context.Request)))
|
||||
_requestHeaders := (*fasthttp.RequestHeader) (NoEscape (unsafe.Pointer (&_context.Request.Header)))
|
||||
_response := (*fasthttp.Response) (NoEscape (unsafe.Pointer (&_context.Response)))
|
||||
|
@ -391,6 +400,50 @@ func ServeDummyRaw (_context *fasthttp.RequestCtx) () {
|
|||
|
||||
|
||||
|
||||
func (_server *server) ServeHTTP (_response http.ResponseWriter, _request *http.Request) () {
|
||||
|
||||
_context := fasthttp.RequestCtx {}
|
||||
_context.Request.Reset ()
|
||||
_context.Response.Reset ()
|
||||
|
||||
_context.Request.Header.SetMethod (_request.Method)
|
||||
_context.Request.Header.SetRequestURI (_request.URL.Path)
|
||||
|
||||
_server.Serve (&_context)
|
||||
|
||||
{
|
||||
_buffer := bytes.NewBuffer (make ([]byte, 0, 4096))
|
||||
_writer := bufio.NewWriter (_buffer)
|
||||
_context.Response.Header.Write (_writer)
|
||||
_writer.Flush ()
|
||||
_context.Response.Header.Read (bufio.NewReader (_buffer))
|
||||
}
|
||||
_responseBody := _context.Response.Body ()
|
||||
|
||||
_responseHeaders := _response.Header ()
|
||||
_context.Response.Header.VisitAll (
|
||||
func (_key_0 []byte, _value_0 []byte) () {
|
||||
switch string (_key_0) {
|
||||
case "Connection" :
|
||||
// NOP
|
||||
default :
|
||||
_key := string (_key_0)
|
||||
_value := string (_value_0)
|
||||
_responseHeaders[_key] = append (_responseHeaders[_key], _value)
|
||||
}
|
||||
})
|
||||
|
||||
if len (_responseBody) > 0 {
|
||||
_responseHeaders["Content-Length"] = []string { fmt.Sprintf ("%d", len (_responseBody)) }
|
||||
}
|
||||
|
||||
_response.WriteHeader (_context.Response.Header.StatusCode ())
|
||||
_response.Write (_responseBody)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func Main () () {
|
||||
Main_0 (main_0)
|
||||
}
|
||||
|
@ -400,6 +453,7 @@ func main_0 () (error) {
|
|||
|
||||
|
||||
var _bind string
|
||||
var _bindTls string
|
||||
var _archivePath string
|
||||
var _archiveInmem bool
|
||||
var _archiveMmap bool
|
||||
|
@ -414,6 +468,7 @@ func main_0 () (error) {
|
|||
var _threads uint
|
||||
var _slave uint
|
||||
var _debug bool
|
||||
var _quiet bool
|
||||
var _dummy bool
|
||||
var _isFirst bool
|
||||
var _isMaster bool
|
||||
|
@ -441,6 +496,7 @@ func main_0 () (error) {
|
|||
kawipiko-server
|
||||
|
||||
--bind <ip>:<port>
|
||||
--bind-tls <ip>:<port>
|
||||
|
||||
--processes <count> (of slave processes)
|
||||
--threads <count> (of threads per process)
|
||||
|
@ -472,6 +528,7 @@ func main_0 () (error) {
|
|||
}
|
||||
|
||||
_bind_0 := _flags.String ("bind", "", "")
|
||||
_bindTls_0 := _flags.String ("bind-tls", "", "")
|
||||
_archivePath_0 := _flags.String ("archive", "", "")
|
||||
_archiveInmem_0 := _flags.Bool ("archive-inmem", false, "")
|
||||
_archiveMmap_0 := _flags.Bool ("archive-mmap", false, "")
|
||||
|
@ -489,11 +546,13 @@ func main_0 () (error) {
|
|||
_profileCpu_0 := _flags.String ("profile-cpu", "", "")
|
||||
_profileMem_0 := _flags.String ("profile-mem", "", "")
|
||||
_debug_0 := _flags.Bool ("debug", false, "")
|
||||
_quiet_0 := _flags.Bool ("quiet", false, "")
|
||||
_dummy_0 := _flags.Bool ("dummy", false, "")
|
||||
|
||||
FlagsParse (_flags, 0, 0)
|
||||
|
||||
_bind = *_bind_0
|
||||
_bindTls = *_bindTls_0
|
||||
_archivePath = *_archivePath_0
|
||||
_archiveInmem = *_archiveInmem_0
|
||||
_archiveMmap = *_archiveMmap_0
|
||||
|
@ -509,6 +568,7 @@ func main_0 () (error) {
|
|||
_threads = *_threads_0
|
||||
_slave = *_slave_0
|
||||
_debug = *_debug_0
|
||||
_quiet = *_quiet_0 && !_debug
|
||||
_dummy = *_dummy_0
|
||||
|
||||
_profileCpu = *_profileCpu_0
|
||||
|
@ -521,7 +581,7 @@ func main_0 () (error) {
|
|||
_isFirst = true
|
||||
}
|
||||
|
||||
if _bind == "" {
|
||||
if (_bind == "") && (_bindTls == "") {
|
||||
AbortError (nil, "[6edd9512] expected bind address argument!")
|
||||
}
|
||||
|
||||
|
@ -577,7 +637,7 @@ func main_0 () (error) {
|
|||
|
||||
debug.SetGCPercent (50)
|
||||
debug.SetMaxThreads (int (128 * (_threads / 64 + 1)))
|
||||
debug.SetMaxStack (16 * 1024)
|
||||
// debug.SetMaxStack (16 * 1024)
|
||||
|
||||
|
||||
_httpServerReduceMemory := false
|
||||
|
@ -599,9 +659,12 @@ func main_0 () (error) {
|
|||
|
||||
_processName := os.Args[0]
|
||||
_processArguments := make ([]string, 0, len (os.Args))
|
||||
_processArguments = append (_processArguments,
|
||||
"--bind", _bind,
|
||||
)
|
||||
if _bind != "" {
|
||||
_processArguments = append (_processArguments, "--bind", _bind)
|
||||
}
|
||||
if _bindTls != "" {
|
||||
_processArguments = append (_processArguments, "--bind-tls", _bindTls)
|
||||
}
|
||||
if _archivePath != "" {
|
||||
_processArguments = append (_processArguments, "--archive", _archivePath)
|
||||
}
|
||||
|
@ -635,6 +698,9 @@ func main_0 () (error) {
|
|||
if _debug {
|
||||
_processArguments = append (_processArguments, "--debug")
|
||||
}
|
||||
if _quiet {
|
||||
_processArguments = append (_processArguments, "--quiet")
|
||||
}
|
||||
if _dummy {
|
||||
_processArguments = append (_processArguments, "--dummy")
|
||||
}
|
||||
|
@ -655,7 +721,7 @@ func main_0 () (error) {
|
|||
if _processPid, _error := os.StartProcess (_processName, _processArguments, _processAttributes); _error == nil {
|
||||
_processesJoin.Add (1)
|
||||
_processesPid[_processIndex] = _processPid
|
||||
if _debug {
|
||||
if !_quiet {
|
||||
log.Printf ("[ii] [63cb22f8] sub-process `%d` started (with `%d` threads);\n", _processPid.Pid, _threads)
|
||||
}
|
||||
go func (_index int, _processPid *os.Process) () {
|
||||
|
@ -700,7 +766,7 @@ func main_0 () (error) {
|
|||
|
||||
_processesJoin.Wait ()
|
||||
|
||||
if _debug {
|
||||
if !_quiet {
|
||||
log.Printf ("[ii] [b949bafc] sub-processes terminated;\n")
|
||||
}
|
||||
|
||||
|
@ -716,7 +782,7 @@ func main_0 () (error) {
|
|||
var _cdbReader *cdb.CDB
|
||||
if _archivePath != "" {
|
||||
|
||||
if _debug || _isFirst {
|
||||
if !_quiet && (_debug || _isFirst) {
|
||||
log.Printf ("[ii] [3b788396] opening archive file `%s`...\n", _archivePath)
|
||||
}
|
||||
|
||||
|
@ -745,7 +811,7 @@ func main_0 () (error) {
|
|||
}
|
||||
|
||||
if _archivePreload {
|
||||
if _debug {
|
||||
if !_quiet {
|
||||
log.Printf ("[ii] [13f4ebf7] preloading archive file...\n")
|
||||
}
|
||||
_buffer := [16 * 1024]byte {}
|
||||
|
@ -818,7 +884,7 @@ func main_0 () (error) {
|
|||
|
||||
} else {
|
||||
|
||||
if _debug || _isFirst {
|
||||
if !_quiet && (_debug || _isFirst) {
|
||||
log.Printf ("[ww] [dd697a66] using `read`-based archive (with significant performance impact)!\n")
|
||||
}
|
||||
|
||||
|
@ -856,7 +922,7 @@ func main_0 () (error) {
|
|||
}
|
||||
|
||||
if _indexPaths || _indexDataMeta || _indexDataContent {
|
||||
if _debug {
|
||||
if !_quiet {
|
||||
log.Printf ("[ii] [fa5338fd] indexing archive...\n")
|
||||
}
|
||||
if _filesIndex, _error := _cdbReader.GetWithCdbHash ([]byte (NamespaceFilesIndex)); _error == nil {
|
||||
|
@ -956,6 +1022,7 @@ func main_0 () (error) {
|
|||
securityHeadersTls : _securityHeadersTls,
|
||||
securityHeadersEnabled : _securityHeadersEnabled,
|
||||
debug : _debug,
|
||||
quiet : _quiet,
|
||||
dummy : _dummy,
|
||||
}
|
||||
|
||||
|
@ -1022,51 +1089,147 @@ func main_0 () (error) {
|
|||
|
||||
}
|
||||
|
||||
_httpsServer := & http.Server {
|
||||
|
||||
Handler : _server,
|
||||
TLSConfig : & tls.Config {},
|
||||
|
||||
MaxHeaderBytes : 16 * 1024,
|
||||
|
||||
ReadTimeout : 30 * time.Second,
|
||||
ReadHeaderTimeout : 30 * time.Second,
|
||||
WriteTimeout : 30 * time.Second,
|
||||
IdleTimeout : 360 * time.Second,
|
||||
|
||||
}
|
||||
|
||||
if _timeoutDisabled {
|
||||
|
||||
_httpServer.ReadTimeout = 0
|
||||
_httpServer.WriteTimeout = 0
|
||||
_httpServer.IdleTimeout = 0
|
||||
}
|
||||
|
||||
if _dummy {
|
||||
_httpServer.Handler = _server.ServeDummy
|
||||
}
|
||||
_httpsServer.ReadTimeout = 0
|
||||
_httpsServer.ReadHeaderTimeout = 0
|
||||
_httpsServer.WriteTimeout = 0
|
||||
_httpsServer.IdleTimeout = 1 * time.Second
|
||||
|
||||
_server.httpServer = _httpServer
|
||||
|
||||
|
||||
{
|
||||
_signals := make (chan os.Signal, 32)
|
||||
signal.Notify (_signals, syscall.SIGINT, syscall.SIGTERM)
|
||||
go func () () {
|
||||
<- _signals
|
||||
if _debug {
|
||||
log.Printf ("[ii] [691cb695] shutingdown...\n")
|
||||
}
|
||||
_server.httpServer.Shutdown ()
|
||||
} ()
|
||||
}
|
||||
|
||||
|
||||
if _debug || _isFirst {
|
||||
if !_quiet && (_debug || _isFirst) {
|
||||
if _bind != "" {
|
||||
log.Printf ("[ii] [f11e4e37] listening on `http://%s/`;\n", _bind)
|
||||
}
|
||||
if _bindTls != "" {
|
||||
log.Printf ("[ii] [21f050c3] listening on `https://%s/`;\n", _bindTls)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var _httpListener net.Listener
|
||||
if _httpListener_0, _error := reuseport.Listen ("tcp4", _bind); _error == nil {
|
||||
_httpListener = _httpListener_0
|
||||
if _bind != "" {
|
||||
if _listener_0, _error := reuseport.Listen ("tcp4", _bind); _error == nil {
|
||||
_httpListener = _listener_0
|
||||
} else {
|
||||
AbortError (_error, "[d5f51e9f] failed starting listener!")
|
||||
}
|
||||
}
|
||||
|
||||
if _error := _httpServer.Serve (_httpListener); _error != nil {
|
||||
var _httpsListener net.Listener
|
||||
if _bindTls != "" {
|
||||
if _listener_0, _error := reuseport.Listen ("tcp4", _bindTls); _error == nil {
|
||||
_httpsListener = _listener_0
|
||||
} else {
|
||||
AbortError (_error, "[e35cc693] failed starting listener!")
|
||||
}
|
||||
}
|
||||
if _bindTls != "" {
|
||||
if _certificate, _error := tls.X509KeyPair ([]byte (DefaultTlsCertificatePublic), []byte (DefaultTlsCertificatePrivate)); _error == nil {
|
||||
_httpsServer.TLSConfig.Certificates = append (_httpsServer.TLSConfig.Certificates, _certificate)
|
||||
} else {
|
||||
AbortError (_error, "[98ba6d23] failed parsing TLS certificate!")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if _httpListener != nil {
|
||||
_server.httpServer = _httpServer
|
||||
}
|
||||
if _httpsListener != nil {
|
||||
_server.httpsServer = _httpsServer
|
||||
}
|
||||
|
||||
_httpServer = nil
|
||||
_httpsServer = nil
|
||||
|
||||
|
||||
var _waiter sync.WaitGroup
|
||||
|
||||
if _server.httpServer != nil {
|
||||
_waiter.Add (1)
|
||||
go func () () {
|
||||
defer _waiter.Done ()
|
||||
if !_quiet {
|
||||
log.Printf ("[ii] [f2061f1b] starting HTTP server...\n")
|
||||
}
|
||||
if _error := _server.httpServer.Serve (_httpListener); _error != nil {
|
||||
AbortError (_error, "[44f45c67] failed executing server!")
|
||||
}
|
||||
if !_quiet {
|
||||
log.Printf ("[ii] [aca4a14f] stopped HTTP server;\n")
|
||||
}
|
||||
} ()
|
||||
}
|
||||
|
||||
if _server.httpsServer != nil {
|
||||
_waiter.Add (1)
|
||||
go func () () {
|
||||
defer _waiter.Done ()
|
||||
if !_quiet {
|
||||
log.Printf ("[ii] [46ec2e41] starting HTTPS server...\n")
|
||||
}
|
||||
if _error := _server.httpsServer.ServeTLS (_httpsListener, "", ""); (_error != nil) && (_error != http.ErrServerClosed) {
|
||||
AbortError (_error, "[9f6d28f4] failed executing server!")
|
||||
}
|
||||
if !_quiet {
|
||||
log.Printf ("[ii] [9a487770] stopped HTTPS server;\n")
|
||||
}
|
||||
} ()
|
||||
}
|
||||
|
||||
{
|
||||
_waiter.Add (1)
|
||||
_signals := make (chan os.Signal, 32)
|
||||
signal.Notify (_signals, syscall.SIGINT, syscall.SIGTERM)
|
||||
go func () () {
|
||||
defer _waiter.Done ()
|
||||
<- _signals
|
||||
if !_quiet {
|
||||
log.Printf ("[ii] [691cb695] shutingdown (1)...\n")
|
||||
}
|
||||
if _server.httpServer != nil {
|
||||
if !_quiet {
|
||||
log.Printf ("[ii] [8eea3f63] stopping HTTP server...\n")
|
||||
}
|
||||
_server.httpServer.Shutdown ()
|
||||
}
|
||||
if _server.httpsServer != nil {
|
||||
if !_quiet {
|
||||
log.Printf ("[ii] [9ae5a25b] stopping HTTPS server...\n")
|
||||
}
|
||||
_server.httpsServer.Close ()
|
||||
}
|
||||
} ()
|
||||
}
|
||||
|
||||
_waiter.Wait ()
|
||||
|
||||
|
||||
if _debug {
|
||||
if !_quiet {
|
||||
defer log.Printf ("[ii] [a49175db] done!\n")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
67
sources/lib/server/tls.go
Normal file
67
sources/lib/server/tls.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
|
||||
|
||||
package server
|
||||
|
||||
|
||||
|
||||
|
||||
var DefaultTlsCertificatePublic = []byte (`
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDIzCCAgugAwIBAgIUVyUIITgu0+by4ASAy3b9vOM+B2wwDQYJKoZIhvcNAQEL
|
||||
BQAwHzEdMBsGA1UEAxMUa2F3aXBpa28udm9sdXRpb24ucm8wIBcNMTkwODE0MTUw
|
||||
OTEzWhgPMjA1OTA4MTQxNTA5MTNaMB8xHTAbBgNVBAMTFGthd2lwaWtvLnZvbHV0
|
||||
aW9uLnJvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvo6I70Xe87KO
|
||||
aj764hlWEcAWWaEnBmzMgJtOiAgFfG6B3vMuSE84Ro7a0uqVwkHqhYOrE66jFBo8
|
||||
moPBOBABovVpDtNGjWGE+xFqf609MEuWloDNu4d6wgBjdjcXfZZ6KYcsfsctcoRe
|
||||
eYljgujx+lvRgORKS4nWnOOyY3O9wJRMxa3ITkRfVUwlQgampKKcIk3iXdRqdAOt
|
||||
ws6TO3VTwVZ1poDDSyYcKTW6aQoQmsOCDEgQh+pyYQJSVIEqiFP32cjq43opHonf
|
||||
OpykAiL2e7MiRYJur5E5xH2ZmT9SersPcACMoCu1DiHPJaGvxfl693gf4pgX6rDb
|
||||
PWTNJqWpqwIDAQABo1UwUzAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUF
|
||||
BwMBMA8GA1UdDwEB/wQFAwMHoAAwHQYDVR0OBBYEFPDjABVCI490LdvHPeotzNq3
|
||||
xa9KMA0GCSqGSIb3DQEBCwUAA4IBAQA0cYKpYneOgBRGL/5q86g17qGOrQOWjdDr
|
||||
1k7i817pBjIfRj9bm1n2iaSrC4GCt4Ok+hl/DyjPNDDUXZxEmfmxlugi6dKLPQp9
|
||||
p30hlTB7E3ArHKkWXYGo19URewAUYOMEIR1lB5/RS21rnpUKHawrwi9pZHTwYQ5Q
|
||||
QcnpA9/FvCbPo8gb9kPAuDyj39tdzzgNK/Xvj8ym9RhUbTtBgbWujRCIWU0L6bfl
|
||||
i7DLfJoPSK+s6S5YGr88VAz0y9zAGD/2wGq9R1hUSDw0OfMgEm9GoSz6FpXKKBtl
|
||||
M01bP11akztK8sWChdels4OXOsPQ1SdF2XE4od82cm6lA8IgE1hY
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
`)
|
||||
|
||||
|
||||
|
||||
|
||||
var DefaultTlsCertificatePrivate = []byte (`
|
||||
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC+jojvRd7zso5q
|
||||
PvriGVYRwBZZoScGbMyAm06ICAV8boHe8y5ITzhGjtrS6pXCQeqFg6sTrqMUGjya
|
||||
g8E4EAGi9WkO00aNYYT7EWp/rT0wS5aWgM27h3rCAGN2Nxd9lnophyx+xy1yhF55
|
||||
iWOC6PH6W9GA5EpLidac47Jjc73AlEzFrchORF9VTCVCBqakopwiTeJd1Gp0A63C
|
||||
zpM7dVPBVnWmgMNLJhwpNbppChCaw4IMSBCH6nJhAlJUgSqIU/fZyOrjeikeid86
|
||||
nKQCIvZ7syJFgm6vkTnEfZmZP1J6uw9wAIygK7UOIc8loa/F+Xr3eB/imBfqsNs9
|
||||
ZM0mpamrAgMBAAECggEAORjSVQeVj2XAIHuwhtDapkTtLXwJCnbNK/fdJwtoQWmH
|
||||
RnuNMaNzFEk3rh0WNHe1wr26JBKe0KYv5Ih3+8loBCEOkp+hszk2NFh6lbkd7Xuo
|
||||
qn37pyYoFTsykjhdtIbDIfBb17zslDSvbjFJfO85mi+q7bj5vfqWMLpVOFF02N/S
|
||||
SmASAzAYTAOE+wheMuTWkm8r3PXh8WhJViWLp/9l6gyLT0mOazxaVayOWyJ/pg1w
|
||||
qPZiNOavTbNyP7jzUysA4LX9CdBQx3k48IQm0c59Zu49Rl7H6ZT9Vp2CSkvbZRZS
|
||||
qVLKYtE4o5SIyAPI5QBCRyNVkHQnZAzPIv/vwbky4QKBgQDmcxY9YVIVpjZQCcVg
|
||||
R++ClrjKKzuR4dmUvmF3H6F4uT6S+7zPsaaIbgBUo2B/Z5QZ+vv6FeKcGZhGSVzU
|
||||
gtiQeNvEPE25oHbJm3ui71Wvw2mEpTp52bYL6k68b45ydq/CCpohSLym/WjlVVSz
|
||||
ce2IJZaviGn68jY175bRRDAb2wKBgQDTrykGt8gfACmSBZcULkaXCDqT0nfnWccx
|
||||
OHuimbIDgSU0Q/KJA9P0pSbtL/2rUXEnZpUJ0oDDEi0MpBkSX3Tb3U959aY97hXK
|
||||
arHI0iziUcW1ZZ2XGO5KtRviQ0D5CKZWR1Ttjm1oCJkmxAag070CF/UdcTGEizrK
|
||||
OeI7o1l6cQKBgBo21z3ON0ctLBp4shIcvLsPKCAfQNx8Y4LPEUk6uOSBtgOETVsW
|
||||
60mzsafvGcgEYU1/RnCRUsDNDIxaRgwKglYU2XL+JR1Lipeubyb+sLGYugUTwo4f
|
||||
3NyIH8LBseOFasLY7+V/X65jPy5vQX5UJGALXpPDIcMhEFecVHyjlBFnAoGABtWs
|
||||
+W6No5KZxQExM5Ga7d1yJruw62NWrxwnwcQ8nyhYTyuydQIOoeODMj1Ob22dvavu
|
||||
O/bz+Vho4/OYa6NxXnfyzPlFeNJrGbIAM3+1u0jwnT6+q9Y+O2NFlzScsG27ESYU
|
||||
c+cZWTaN21aQ8Dhl7d9gJqc09haYu1bLGynXBcECgYEAsxgIbbO3CtxPfqgtJrAo
|
||||
eRPPLX7UOdXmarOBYFL+jsG5SWSyECqKDgkjyeQFVqHzK+W4k654TobZoMUhDIUL
|
||||
GeNAoNAIjPciush/0yYI8w3EybHIkB6JSi4LyhWBQazGaAr3Ai0NHbKt3ZzcOM1D
|
||||
azCipM9H6CJO+MjoG+S53Xo=
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
`)
|
||||
|
Loading…
Reference in a new issue