✨ Fetch userinfo in auth middleware
This commit is contained in:
5
pkg/nex/const.go
Normal file
5
pkg/nex/const.go
Normal file
@ -0,0 +1,5 @@
|
||||
package nex
|
||||
|
||||
const (
|
||||
ServiceTypeAuth = "id"
|
||||
)
|
35
pkg/nex/sec/info.go
Normal file
35
pkg/nex/sec/info.go
Normal file
@ -0,0 +1,35 @@
|
||||
package sec
|
||||
|
||||
import (
|
||||
"git.solsynth.dev/hypernet/nexus/pkg/nex"
|
||||
"git.solsynth.dev/hypernet/nexus/pkg/proto"
|
||||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
// UserInfo is the basic of userinfo, you can add anything above it.
|
||||
// Full data from id service was stored in the metadata field.
|
||||
type UserInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PermNodes map[string]any `json:"perm_nodes"`
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
}
|
||||
|
||||
func NewUserInfoFromProto(in *proto.UserInfo) UserInfo {
|
||||
return UserInfo{
|
||||
ID: uint(in.Id),
|
||||
Name: in.Name,
|
||||
PermNodes: nex.DecodeMap(in.PermNodes),
|
||||
Metadata: nex.DecodeMap(in.Metadata),
|
||||
}
|
||||
}
|
||||
|
||||
func NewUserInfoFromBytes(in []byte) (UserInfo, error) {
|
||||
var info UserInfo
|
||||
err := json.Unmarshal(in, &info)
|
||||
return info, err
|
||||
}
|
||||
|
||||
func (v UserInfo) Encode() []byte {
|
||||
return nex.EncodeMap(v)
|
||||
}
|
108
pkg/nex/sec/internal_token.go
Normal file
108
pkg/nex/sec/internal_token.go
Normal file
@ -0,0 +1,108 @@
|
||||
package sec
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type InternalTokenWriter struct {
|
||||
pk *ed25519.PrivateKey
|
||||
}
|
||||
|
||||
func NewInternalTokenWriter(fp string) (*InternalTokenWriter, error) {
|
||||
rawKey, err := os.ReadFile(fp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(rawKey)
|
||||
if block == nil || block.Type != "PRIVATE KEY" {
|
||||
return nil, fmt.Errorf("failed to decode PEM block containing private key")
|
||||
}
|
||||
|
||||
anyPk, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pk, ok := anyPk.(*ed25519.PrivateKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not an Ed25519 private key")
|
||||
}
|
||||
|
||||
return &InternalTokenWriter{
|
||||
pk: pk,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (v *InternalTokenWriter) WriteUserInfoJwt(in UserInfo, audiences ...string) (string, error) {
|
||||
rawData := base64.StdEncoding.EncodeToString(in.Encode())
|
||||
claims := jwt.RegisteredClaims{
|
||||
NotBefore: jwt.NewNumericDate(time.Now()),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(5 * time.Minute)),
|
||||
Audience: audiences,
|
||||
Issuer: "nexus",
|
||||
Subject: rawData,
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodEdDSA, claims)
|
||||
return token.SignedString(v.pk)
|
||||
}
|
||||
|
||||
type InternalTokenReader struct {
|
||||
pk *ed25519.PublicKey
|
||||
}
|
||||
|
||||
func NewInternalTokenReader(fp string) (*InternalTokenReader, error) {
|
||||
rawKey, err := os.ReadFile(fp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(rawKey)
|
||||
if block == nil || block.Type != "PUBLIC KEY" {
|
||||
return nil, fmt.Errorf("failed to decode PEM block containing private key")
|
||||
}
|
||||
|
||||
anyPk, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pk, ok := anyPk.(*ed25519.PublicKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not an Ed25519 public key")
|
||||
}
|
||||
|
||||
return &InternalTokenReader{
|
||||
pk: pk,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (v *InternalTokenReader) ReadUserInfoJwt(in string) (*UserInfo, error) {
|
||||
token, err := jwt.ParseWithClaims(in, &jwt.RegisteredClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return v.pk, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !token.Valid {
|
||||
return nil, fmt.Errorf("invalid token")
|
||||
}
|
||||
claims, ok := token.Claims.(*jwt.RegisteredClaims)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid claims")
|
||||
}
|
||||
rawData, err := base64.StdEncoding.DecodeString(claims.Subject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info, err := NewUserInfoFromBytes(rawData)
|
||||
return &info, err
|
||||
}
|
@ -14,12 +14,12 @@ type JwtReader struct {
|
||||
}
|
||||
|
||||
func NewJwtReader(fp string) (*JwtReader, error) {
|
||||
privateKeyBytes, err := os.ReadFile(fp)
|
||||
rawKey, err := os.ReadFile(fp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(privateKeyBytes)
|
||||
block, _ := pem.Decode(rawKey)
|
||||
if block == nil || block.Type != "PUBLIC KEY" {
|
||||
return nil, fmt.Errorf("failed to decode PEM block containing private key")
|
||||
}
|
||||
|
@ -14,12 +14,12 @@ type JwtWriter struct {
|
||||
}
|
||||
|
||||
func NewJwtWriter(fp string) (*JwtWriter, error) {
|
||||
rawPk, err := os.ReadFile(fp)
|
||||
rawKey, err := os.ReadFile(fp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(rawPk)
|
||||
block, _ := pem.Decode(rawKey)
|
||||
if block == nil || block.Type != "PRIVATE KEY" {
|
||||
return nil, fmt.Errorf("failed to decode PEM block containing private key")
|
||||
}
|
||||
@ -41,9 +41,5 @@ func NewJwtWriter(fp string) (*JwtWriter, error) {
|
||||
|
||||
func WriteJwt[T jwt.Claims](v *JwtWriter, in T) (string, error) {
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodRS256, in)
|
||||
ss, err := token.SignedString(v.key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ss, nil
|
||||
return token.SignedString(v.key)
|
||||
}
|
||||
|
Reference in New Issue
Block a user