Move jwt keys to database

Moved code for it to one place
Updated to chi v5
This commit is contained in:
Jamie Curnow 2023-05-26 14:50:41 +10:00
parent 29990110b1
commit ceb62fb0f2
No known key found for this signature in database
GPG Key ID: FFBB624C43388E9E
12 changed files with 168 additions and 139 deletions

View File

@ -14,6 +14,7 @@ import (
"npm/internal/entity/user"
"npm/internal/errors"
"npm/internal/jobqueue"
"npm/internal/jwt"
"npm/internal/logger"
)
@ -26,6 +27,11 @@ func main() {
config.Init(&version, &commit, &sentryDSN)
database.Migrate(func() {
if err := jwt.LoadKeys(); err != nil {
logger.Error("KeysError", err)
os.Exit(1)
}
setting.ApplySettings()
checkSetup()

View File

@ -1,5 +1,15 @@
-- migrate:up
CREATE TABLE IF NOT EXISTS `keys`
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at INTEGER NOT NULL DEFAULT 0,
updated_at INTEGER NOT NULL DEFAULT 0,
is_deleted INTEGER NOT NULL DEFAULT 0,
public_key TEXT NOT NULL,
private_key TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS `user`
(
id INTEGER PRIMARY KEY AUTOINCREMENT,

View File

@ -12,8 +12,10 @@ require (
github.com/getsentry/sentry-go v0.21.0
github.com/glebarez/sqlite v1.8.0
github.com/go-chi/chi v4.1.2+incompatible
github.com/go-chi/chi/v5 v5.0.8
github.com/go-chi/cors v1.2.1
github.com/go-chi/jwtauth v4.0.4+incompatible
github.com/go-chi/jwtauth/v5 v5.1.0
github.com/jc21/go-sse v0.0.0-20230307071053-2e6b1dbcb7ec
github.com/jc21/jsref v0.0.0-20210608024405-a97debfc4760
github.com/patrickmn/go-cache v2.1.0+incompatible
@ -32,16 +34,23 @@ require (
require (
github.com/alexflint/go-scalar v1.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/glebarez/go-sqlite v1.21.1 // indirect
github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.3.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/lestrrat-go/blackmagic v1.0.1 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.4 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/jspointer v0.0.0-20181205001929-82fadba7561c // indirect
github.com/lestrrat-go/jwx/v2 v2.0.6 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/lestrrat-go/pdebug/v3 v3.0.1 // indirect
github.com/lestrrat-go/structinfo v0.0.0-20210312050401-7f8bd69d6acb // indirect

View File

@ -11,6 +11,9 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/drexedam/gravatar v0.0.0-20210327211422-e94eea8c338e h1:2R8DvYLNr5DL25eWwpOdPno1eIbTNjJC0d7v8ti5cus=
@ -27,14 +30,20 @@ github.com/glebarez/sqlite v1.8.0 h1:02X12E2I/4C1n+v90yTqrjRa8yuo7c3KeHI3FRznCvc
github.com/glebarez/sqlite v1.8.0/go.mod h1:bpET16h1za2KOOMb8+jCp6UBP/iahDpfPQqSaYLTLx8=
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/jwtauth v4.0.4+incompatible h1:LGIxg6YfvSBzxU2BljXbrzVc1fMlgqSKBQgKOGAVtPY=
github.com/go-chi/jwtauth v4.0.4+incompatible/go.mod h1:Q5EIArY/QnD6BdS+IyDw7B2m6iNbnPxtfd6/BcmtWbs=
github.com/go-chi/jwtauth/v5 v5.1.0 h1:wJyf2YZ/ohPvNJBwPOzZaQbyzwgMZZceE1m8FOzXLeA=
github.com/go-chi/jwtauth/v5 v5.1.0/go.mod h1:MA93hc1au3tAQwCKry+fI4LqJ5MIVN4XSsglOo+lSc8=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
@ -64,9 +73,20 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kyoh86/richgo v0.3.8/go.mod h1:2C8POkF1H04iTOG2Tp1yyZhspCME9nN3cir3VXJ02II=
github.com/kyoh86/xdg v1.2.0/go.mod h1:/mg8zwu1+qe76oTFUBnyS7rJzk7LLC0VGEzJyJ19DHs=
github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80=
github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJGdI8=
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
github.com/lestrrat-go/jspointer v0.0.0-20181205001929-82fadba7561c h1:pGh5EFIfczeDHwgMHgfwjhZzL+8/E3uZF6T7vER/W8c=
github.com/lestrrat-go/jspointer v0.0.0-20181205001929-82fadba7561c/go.mod h1:xw2Gm4Mg+ST9s8fHR1VkUIyOJMJnSloRZlPQB+wyVpY=
github.com/lestrrat-go/jwx/v2 v2.0.6 h1:RlyYNLV892Ed7+FTfj1ROoF6x7WxL965PGTHso/60G0=
github.com/lestrrat-go/jwx/v2 v2.0.6/go.mod h1:aVrGuwEr3cp2Prw6TtQvr8sQxe+84gruID5C9TxT64Q=
github.com/lestrrat-go/option v0.0.0-20210103042652-6f1ecfceda35/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lestrrat-go/pdebug/v3 v3.0.1 h1:3G5sX/aw/TbMTtVc9U7IHBWRZtMvwvBziF1e4HoQtv8=
@ -126,18 +146,25 @@ github.com/vrischmann/envconfig v1.3.0 h1:4XIvQTXznxmWMnjouj0ST5lFo/WAYf5Exgl3x8
github.com/vrischmann/envconfig v1.3.0/go.mod h1:bbvxFYJdRSpXrhS63mBFtKJzkDiNkyArOLXtY6q0kuI=
github.com/wacul/ptr v1.0.0/go.mod h1:BD0gjsZrCwtoR+yWDB9v2hQ8STlq9tT84qKfa+3txOc=
github.com/zenizh/go-capturer v0.0.0-20211219060012-52ea6c8fed04 h1:qXafrlZL1WsJW5OokjraLLRURHiw0OzKHD/RNdspp4w=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210326220804-49726bf1d181/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=

View File

@ -13,7 +13,7 @@ import (
"npm/internal/logger"
"npm/internal/util"
"github.com/go-chi/jwtauth"
"github.com/go-chi/jwtauth/v5"
)
// DecodeAuth decodes an auth header
@ -29,7 +29,7 @@ func DecodeAuth() func(http.Handler) http.Handler {
}
tokenAuth := jwtauth.New("RS256", privateKey, publicKey)
return jwtauth.Verifier(tokenAuth)
return jwtauth.Verify(tokenAuth, jwtauth.TokenFromHeader)
}
// Enforce is a authentication middleware to enforce access from the
@ -44,13 +44,14 @@ func Enforce(permission string) func(http.Handler) http.Handler {
token, claims, err := jwtauth.FromContext(ctx)
if err != nil {
logger.Debug("EnforceError: %+v", err)
h.ResultErrorJSON(w, r, http.StatusUnauthorized, err.Error(), nil)
return
}
userID := uint(claims["uid"].(float64))
_, enabled := user.IsEnabled(userID)
if token == nil || !token.Valid || !enabled {
if token == nil || !enabled {
h.ResultErrorJSON(w, r, http.StatusUnauthorized, "Unauthorised", nil)
return
}

View File

@ -5,7 +5,7 @@ import (
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/go-chi/chi/v5"
)
var methodMap = []string{

View File

@ -12,8 +12,8 @@ import (
"npm/internal/logger"
"npm/internal/serverevents"
"github.com/go-chi/chi"
chiMiddleware "github.com/go-chi/chi/middleware"
"github.com/go-chi/chi/v5"
chiMiddleware "github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors"
)

View File

@ -26,7 +26,6 @@ func Init(version, commit, sentryDSN *string) {
initLogger(*sentryDSN)
logger.Info("Build Version: %s (%s)", Version, Commit)
createDataFolders()
loadKeys()
}
// InitIPRanges will initialise the config for the ipranges command
@ -79,11 +78,3 @@ func initLogger(sentryDSN string) {
func GetLogLevel() logger.Level {
return logLevel
}
func isError(errorClass string, err error) bool {
if err != nil {
logger.Error(errorClass, err)
return true
}
return false
}

View File

@ -1,111 +0,0 @@
package config
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"fmt"
"os"
"npm/internal/logger"
)
var keysFolder string
var publicKeyFile string
var privateKeyFile string
func loadKeys() {
// check if keys folder exists in data folder
keysFolder = fmt.Sprintf("%s/keys", Configuration.DataFolder)
publicKeyFile = fmt.Sprintf("%s/public.key", keysFolder)
privateKeyFile = fmt.Sprintf("%s/private.key", keysFolder)
if _, err := os.Stat(keysFolder); os.IsNotExist(err) {
// nolint:errcheck,gosec
os.Mkdir(keysFolder, 0700)
}
// check if keys exist on disk
_, publicKeyErr := os.Stat(publicKeyFile)
_, privateKeyErr := os.Stat(privateKeyFile)
// generate keys if either one doesn't exist
if os.IsNotExist(publicKeyErr) || os.IsNotExist(privateKeyErr) {
generateKeys()
saveKeys()
}
// Load keys from disk
// nolint:gosec
publicKeyBytes, publicKeyBytesErr := os.ReadFile(publicKeyFile)
// nolint:gosec
privateKeyBytes, privateKeyBytesErr := os.ReadFile(privateKeyFile)
PublicKey = string(publicKeyBytes)
PrivateKey = string(privateKeyBytes)
if isError("PublicKeyReadError", publicKeyBytesErr) || isError("PrivateKeyReadError", privateKeyBytesErr) || PublicKey == "" || PrivateKey == "" {
logger.Warn("There was an error loading keys, proceeding to generate new RSA keys")
generateKeys()
saveKeys()
}
}
func generateKeys() {
reader := rand.Reader
bitSize := 4096
key, err := rsa.GenerateKey(reader, bitSize)
if isError("RSAGenerateError", err) {
return
}
privateKey := &pem.Block{
Type: "PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(key),
}
privateKeyBuffer := new(bytes.Buffer)
err = pem.Encode(privateKeyBuffer, privateKey)
if isError("PrivatePEMEncodeError", err) {
return
}
asn1Bytes, err2 := asn1.Marshal(key.PublicKey)
if isError("RSAMarshalError", err2) {
return
}
publicKey := &pem.Block{
Type: "PUBLIC KEY",
Bytes: asn1Bytes,
}
publicKeyBuffer := new(bytes.Buffer)
err = pem.Encode(publicKeyBuffer, publicKey)
if isError("PublicPEMEncodeError", err) {
return
}
PublicKey = publicKeyBuffer.String()
PrivateKey = privateKeyBuffer.String()
logger.Info("Generated new RSA keys")
}
func saveKeys() {
err := os.WriteFile(publicKeyFile, []byte(PublicKey), 0600)
if err != nil {
logger.Error("PublicKeyWriteError", err)
} else {
logger.Info("Saved Public Key: %s", publicKeyFile)
}
err = os.WriteFile(privateKeyFile, []byte(PrivateKey), 0600)
if err != nil {
logger.Error("PrivateKeyWriteError", err)
} else {
logger.Info("Saved Private Key: %s", privateKeyFile)
}
}

View File

@ -16,12 +16,6 @@ var IsSetup bool
// ErrorReporting defines whether we will send errors to Sentry
var ErrorReporting bool
// PublicKey is the public key
var PublicKey string
// PrivateKey is the private key
var PrivateKey string
var logLevel logger.Level
type log struct {

View File

@ -1,11 +1,14 @@
package jwt
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"npm/internal/config"
"npm/internal/logger"
"github.com/rotisserie/eris"
)
@ -21,12 +24,12 @@ func GetPrivateKey() (*rsa.PrivateKey, error) {
if privateKey == nil {
var blankKey *rsa.PrivateKey
if config.PrivateKey == "" {
if currentKeys.PrivateKey == "" {
return blankKey, eris.New("Could not get Private Key from configuration")
}
var err error
privateKey, err = LoadPemPrivateKey(config.PrivateKey)
privateKey, err = LoadPemPrivateKey(currentKeys.PrivateKey)
if err != nil {
return blankKey, err
}
@ -48,12 +51,12 @@ func GetPublicKey() (*rsa.PublicKey, error) {
if publicKey == nil {
var blankKey *rsa.PublicKey
if config.PublicKey == "" {
return blankKey, eris.New("Could not get Public Key filename, check environment variables")
if currentKeys.PublicKey == "" {
return blankKey, eris.New("Could not get Public Key from configuration")
}
var err error
publicKey, err = LoadPemPublicKey(config.PublicKey)
publicKey, err = LoadPemPublicKey(currentKeys.PublicKey)
if err != nil {
return blankKey, err
}
@ -85,3 +88,48 @@ func LoadPemPublicKey(content string) (*rsa.PublicKey, error) {
return publicKeyFileImported, nil
}
func generateKeys() (KeysModel, error) {
m := KeysModel{}
reader := rand.Reader
bitSize := 4096
key, err := rsa.GenerateKey(reader, bitSize)
if err != nil {
return m, err
}
privateKey := &pem.Block{
Type: "PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(key),
}
privateKeyBuffer := new(bytes.Buffer)
err = pem.Encode(privateKeyBuffer, privateKey)
if err != nil {
return m, err
}
asn1Bytes, err := asn1.Marshal(key.PublicKey)
if err != nil {
return m, err
}
publicKey := &pem.Block{
Type: "PUBLIC KEY",
Bytes: asn1Bytes,
}
publicKeyBuffer := new(bytes.Buffer)
err = pem.Encode(publicKeyBuffer, publicKey)
if err != nil {
return m, err
}
m.PublicKey = publicKeyBuffer.String()
m.PrivateKey = privateKeyBuffer.String()
logger.Info("Generated new RSA keys")
return m, nil
}

View File

@ -0,0 +1,54 @@
package jwt
import (
"npm/internal/database"
"npm/internal/entity"
"npm/internal/logger"
)
var currentKeys KeysModel
// KeysModel is the model
type KeysModel struct {
entity.ModelBase
PublicKey string `gorm:"column:public_key"`
PrivateKey string `gorm:"column:private_key"`
}
// TableName overrides the table name used by gorm
func (KeysModel) TableName() string {
return "keys"
}
// LoadByID will load from an ID
func (m *KeysModel) LoadLatest() error {
db := database.GetDB()
result := db.Order("created_at DESC").First(&m)
return result.Error
}
// Save will save this model to the DB
func (m *KeysModel) Save() error {
db := database.GetDB()
result := db.Save(m)
return result.Error
}
// LoadKeys will load from the database, or generate and save new ones
func LoadKeys() error {
// Try to find in db
if err := currentKeys.LoadLatest(); err != nil {
// Keys probably don't exist, so we need to generate some
if currentKeys, err = generateKeys(); err != nil {
return err
}
// and save them
if err = currentKeys.Save(); err != nil {
return err
}
}
logger.Debug("private: %s", currentKeys.PrivateKey)
logger.Debug("public: %s", currentKeys.PublicKey)
return nil
}