🚚 Auth kit and parser of nexus userinfo token
This commit is contained in:
19
pkg/authkit/models/account_groups.go
Normal file
19
pkg/authkit/models/account_groups.go
Normal file
@ -0,0 +1,19 @@
|
||||
package models
|
||||
|
||||
import "gorm.io/datatypes"
|
||||
|
||||
type AccountGroup struct {
|
||||
BaseModel
|
||||
|
||||
Name string `json:"name"`
|
||||
PermNodes datatypes.JSONMap `json:"perm_nodes"`
|
||||
}
|
||||
|
||||
type AccountGroupMember struct {
|
||||
BaseModel
|
||||
|
||||
Account Account `json:"account"`
|
||||
Group AccountGroup `json:"group"`
|
||||
AccountID uint `json:"account_id"`
|
||||
GroupID uint `json:"group_id"`
|
||||
}
|
76
pkg/authkit/models/accounts.go
Normal file
76
pkg/authkit/models/accounts.go
Normal file
@ -0,0 +1,76 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gorm.io/datatypes"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type Account struct {
|
||||
BaseModel
|
||||
|
||||
Name string `json:"name" gorm:"uniqueIndex"`
|
||||
Nick string `json:"nick"`
|
||||
Description string `json:"description"`
|
||||
Avatar *string `json:"avatar"`
|
||||
Banner *string `json:"banner"`
|
||||
ConfirmedAt *time.Time `json:"confirmed_at"`
|
||||
SuspendedAt *time.Time `json:"suspended_at"`
|
||||
PermNodes datatypes.JSONMap `json:"perm_nodes"`
|
||||
|
||||
AutomatedBy *Account `json:"automated_by" gorm:"foreignKey:AutomatedID"`
|
||||
AutomatedID *uint `json:"automated_id"`
|
||||
|
||||
AffiliatedTo *Realm `json:"affiliated_to" gorm:"foreignKey:AffiliatedID"`
|
||||
AffiliatedID *uint `json:"affiliated_id"`
|
||||
|
||||
Profile AccountProfile `json:"profile,omitempty"`
|
||||
Contacts []AccountContact `json:"contacts,omitempty"`
|
||||
Badges []Badge `json:"badges,omitempty"`
|
||||
|
||||
Tickets []AuthTicket `json:"tickets,omitempty"`
|
||||
Factors []AuthFactor `json:"factors,omitempty"`
|
||||
|
||||
Relations []AccountRelationship `json:"relations,omitempty" gorm:"foreignKey:AccountID"`
|
||||
}
|
||||
|
||||
func (v Account) GetAvatar() *string {
|
||||
if v.Avatar != nil {
|
||||
return lo.ToPtr(fmt.Sprintf("%s/%s", viper.GetString("content_endpoint"), *v.Avatar))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v Account) GetBanner() *string {
|
||||
if v.Banner != nil {
|
||||
return lo.ToPtr(fmt.Sprintf("%s/%s", viper.GetString("content_endpoint"), *v.Banner))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v Account) GetPrimaryEmail() AccountContact {
|
||||
val, _ := lo.Find(v.Contacts, func(item AccountContact) bool {
|
||||
return item.Type == EmailAccountContact && item.IsPrimary
|
||||
})
|
||||
return val
|
||||
}
|
||||
|
||||
type AccountContactType = int8
|
||||
|
||||
const (
|
||||
EmailAccountContact = AccountContactType(iota)
|
||||
)
|
||||
|
||||
type AccountContact struct {
|
||||
BaseModel
|
||||
|
||||
Type int8 `json:"type"`
|
||||
Content string `json:"content" gorm:"uniqueIndex"`
|
||||
IsPublic bool `json:"is_public"`
|
||||
IsPrimary bool `json:"is_primary"`
|
||||
VerifiedAt *time.Time `json:"verified_at"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
13
pkg/authkit/models/audit.go
Normal file
13
pkg/authkit/models/audit.go
Normal file
@ -0,0 +1,13 @@
|
||||
package models
|
||||
|
||||
import "gorm.io/datatypes"
|
||||
|
||||
type AuditRecord struct {
|
||||
BaseModel
|
||||
|
||||
Action string `json:"action"`
|
||||
Metadata datatypes.JSONMap `json:"metadata"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
IpAddress string `json:"ip_address"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
80
pkg/authkit/models/auth.go
Normal file
80
pkg/authkit/models/auth.go
Normal file
@ -0,0 +1,80 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
)
|
||||
|
||||
type AuthConfig struct {
|
||||
MaximumAuthSteps int `json:"maximum_auth_steps" validate:"required,min=1,max=99"`
|
||||
}
|
||||
|
||||
type AuthFactorType = int8
|
||||
|
||||
const (
|
||||
PasswordAuthFactor = AuthFactorType(iota)
|
||||
EmailPasswordFactor
|
||||
)
|
||||
|
||||
type AuthFactor struct {
|
||||
BaseModel
|
||||
|
||||
Type int8 `json:"type"`
|
||||
Secret string `json:"-"`
|
||||
Config JSONMap `json:"config"`
|
||||
|
||||
Account Account `json:"account"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
||||
|
||||
type AuthTicket struct {
|
||||
BaseModel
|
||||
|
||||
Location string `json:"location"`
|
||||
IpAddress string `json:"ip_address"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
StepRemain int `json:"step_remain"`
|
||||
Claims datatypes.JSONSlice[string] `json:"claims"`
|
||||
Audiences datatypes.JSONSlice[string] `json:"audiences"`
|
||||
FactorTrail datatypes.JSONSlice[int] `json:"factor_trail"`
|
||||
GrantToken *string `json:"grant_token"`
|
||||
AccessToken *string `json:"access_token"`
|
||||
RefreshToken *string `json:"refresh_token"`
|
||||
ExpiredAt *time.Time `json:"expired_at"`
|
||||
AvailableAt *time.Time `json:"available_at"`
|
||||
LastGrantAt *time.Time `json:"last_grant_at"`
|
||||
Nonce *string `json:"nonce"`
|
||||
ClientID *uint `json:"client_id"`
|
||||
|
||||
Account Account `json:"account"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
||||
|
||||
func (v AuthTicket) IsAvailable() error {
|
||||
if v.StepRemain > 0 {
|
||||
return fmt.Errorf("ticket isn't authenticated yet")
|
||||
}
|
||||
if v.AvailableAt != nil && time.Now().Unix() < v.AvailableAt.Unix() {
|
||||
return fmt.Errorf("ticket isn't available yet")
|
||||
}
|
||||
if v.ExpiredAt != nil && time.Now().Unix() > v.ExpiredAt.Unix() {
|
||||
return fmt.Errorf("ticket expired")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v AuthTicket) IsCanBeAvailble() error {
|
||||
if v.StepRemain > 0 {
|
||||
return fmt.Errorf("ticket isn't authenticated yet")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type AuthContext struct {
|
||||
Ticket AuthTicket `json:"ticket"`
|
||||
Account Account `json:"account"`
|
||||
}
|
11
pkg/authkit/models/badges.go
Normal file
11
pkg/authkit/models/badges.go
Normal file
@ -0,0 +1,11 @@
|
||||
package models
|
||||
|
||||
import "gorm.io/datatypes"
|
||||
|
||||
type Badge struct {
|
||||
BaseModel
|
||||
|
||||
Type string `json:"type"`
|
||||
Metadata datatypes.JSONMap `json:"metadata"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
17
pkg/authkit/models/base.go
Normal file
17
pkg/authkit/models/base.go
Normal file
@ -0,0 +1,17 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type JSONMap = datatypes.JSONType[map[string]any]
|
||||
|
||||
type BaseModel struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
|
||||
}
|
13
pkg/authkit/models/bot.go
Normal file
13
pkg/authkit/models/bot.go
Normal file
@ -0,0 +1,13 @@
|
||||
package models
|
||||
|
||||
type ApiKey struct {
|
||||
BaseModel
|
||||
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Lifecycle *int64 `json:"lifecycle"`
|
||||
Ticket AuthTicket `json:"ticket" gorm:"TicketID"`
|
||||
TicketID uint `json:"ticket_id"`
|
||||
Account Account `json:"account"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
16
pkg/authkit/models/clients.go
Normal file
16
pkg/authkit/models/clients.go
Normal file
@ -0,0 +1,16 @@
|
||||
package models
|
||||
|
||||
import "gorm.io/datatypes"
|
||||
|
||||
type ThirdClient struct {
|
||||
BaseModel
|
||||
|
||||
Alias string `json:"alias" gorm:"uniqueIndex"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Secret string `json:"secret"`
|
||||
Urls datatypes.JSONSlice[string] `json:"urls"`
|
||||
Callbacks datatypes.JSONSlice[string] `json:"callbacks"`
|
||||
IsDraft bool `json:"is_draft"`
|
||||
AccountID *uint `json:"account_id"`
|
||||
}
|
14
pkg/authkit/models/events.go
Normal file
14
pkg/authkit/models/events.go
Normal file
@ -0,0 +1,14 @@
|
||||
package models
|
||||
|
||||
type ActionEvent struct {
|
||||
BaseModel
|
||||
|
||||
Type string `json:"type"`
|
||||
Target string `json:"target"`
|
||||
Location string `json:"location"`
|
||||
IpAddress string `json:"ip_address"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
|
||||
Account Account `json:"account"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
42
pkg/authkit/models/notifications.go
Normal file
42
pkg/authkit/models/notifications.go
Normal file
@ -0,0 +1,42 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"gorm.io/datatypes"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Notification struct {
|
||||
BaseModel
|
||||
|
||||
Topic string `json:"topic"`
|
||||
Title string `json:"title"`
|
||||
Subtitle string `json:"subtitle"`
|
||||
Body string `json:"body"`
|
||||
Metadata datatypes.JSONMap `json:"metadata"`
|
||||
Priority int `json:"priority"`
|
||||
SenderID *uint `json:"sender_id"`
|
||||
|
||||
Account Account `json:"account"`
|
||||
AccountID uint `json:"account_id"`
|
||||
|
||||
ReadAt *time.Time `json:"read_at"`
|
||||
|
||||
IsRealtime bool `json:"is_realtime" gorm:"-"`
|
||||
}
|
||||
|
||||
const (
|
||||
NotifySubscriberFirebase = "firebase"
|
||||
NotifySubscriberAPNs = "apple"
|
||||
)
|
||||
|
||||
type NotificationSubscriber struct {
|
||||
BaseModel
|
||||
|
||||
UserAgent string `json:"user_agent"`
|
||||
Provider string `json:"provider"`
|
||||
DeviceID string `json:"device_id" gorm:"uniqueIndex"`
|
||||
DeviceToken string `json:"device_token"`
|
||||
|
||||
Account Account `json:"account"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
19
pkg/authkit/models/preferences.go
Normal file
19
pkg/authkit/models/preferences.go
Normal file
@ -0,0 +1,19 @@
|
||||
package models
|
||||
|
||||
import "gorm.io/datatypes"
|
||||
|
||||
type PreferenceAuth struct {
|
||||
BaseModel
|
||||
|
||||
Config datatypes.JSONType[AuthConfig] `json:"config"`
|
||||
AccountID uint `json:"account_id"`
|
||||
Account Account `json:"account"`
|
||||
}
|
||||
|
||||
type PreferenceNotification struct {
|
||||
BaseModel
|
||||
|
||||
Config datatypes.JSONMap `json:"config"`
|
||||
AccountID uint `json:"account_id"`
|
||||
Account Account `json:"account"`
|
||||
}
|
16
pkg/authkit/models/profiles.go
Normal file
16
pkg/authkit/models/profiles.go
Normal file
@ -0,0 +1,16 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type AccountProfile struct {
|
||||
BaseModel
|
||||
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Experience uint64 `json:"experience"`
|
||||
LastSeenAt *time.Time `json:"last_seen_at"`
|
||||
Birthday *time.Time `json:"birthday"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
28
pkg/authkit/models/realms.go
Normal file
28
pkg/authkit/models/realms.go
Normal file
@ -0,0 +1,28 @@
|
||||
package models
|
||||
|
||||
import "gorm.io/datatypes"
|
||||
|
||||
type Realm struct {
|
||||
BaseModel
|
||||
|
||||
Alias string `json:"alias" gorm:"uniqueIndex"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Members []RealmMember `json:"members"`
|
||||
Avatar *string `json:"avatar"`
|
||||
Banner *string `json:"banner"`
|
||||
AccessPolicy datatypes.JSONMap `json:"access_policy"`
|
||||
IsPublic bool `json:"is_public"`
|
||||
IsCommunity bool `json:"is_community"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
||||
|
||||
type RealmMember struct {
|
||||
BaseModel
|
||||
|
||||
RealmID uint `json:"realm_id"`
|
||||
AccountID uint `json:"account_id"`
|
||||
Realm Realm `json:"realm"`
|
||||
Account Account `json:"account"`
|
||||
PowerLevel int `json:"power_level"`
|
||||
}
|
23
pkg/authkit/models/relationships.go
Normal file
23
pkg/authkit/models/relationships.go
Normal file
@ -0,0 +1,23 @@
|
||||
package models
|
||||
|
||||
import "gorm.io/datatypes"
|
||||
|
||||
type RelationshipStatus = int8
|
||||
|
||||
const (
|
||||
RelationshipPending = RelationshipStatus(iota)
|
||||
RelationshipFriend
|
||||
RelationshipBlocked
|
||||
RelationshipWaiting
|
||||
)
|
||||
|
||||
type AccountRelationship struct {
|
||||
BaseModel
|
||||
|
||||
AccountID uint `json:"account_id"`
|
||||
RelatedID uint `json:"related_id"`
|
||||
Account Account `json:"account"`
|
||||
Related Account `json:"related"`
|
||||
Status RelationshipStatus `json:"status"`
|
||||
PermNodes datatypes.JSONMap `json:"perm_nodes"`
|
||||
}
|
19
pkg/authkit/models/reports.go
Normal file
19
pkg/authkit/models/reports.go
Normal file
@ -0,0 +1,19 @@
|
||||
package models
|
||||
|
||||
const (
|
||||
ReportStatusPending = "pending"
|
||||
ReportStatusReviewing = "reviewing"
|
||||
ReportStatusConfirmed = "confirmed"
|
||||
ReportStatusRejected = "rejected"
|
||||
ReportStatusProcessed = "processed"
|
||||
)
|
||||
|
||||
type AbuseReport struct {
|
||||
BaseModel
|
||||
|
||||
Resource string `json:"resource"`
|
||||
Reason string `json:"reason"`
|
||||
Status string `json:"status"`
|
||||
AccountID uint `json:"account_id"`
|
||||
Account Account `json:"account"`
|
||||
}
|
10
pkg/authkit/models/sign_record.go
Normal file
10
pkg/authkit/models/sign_record.go
Normal file
@ -0,0 +1,10 @@
|
||||
package models
|
||||
|
||||
type SignRecord struct {
|
||||
BaseModel
|
||||
|
||||
ResultTier int `json:"result_tier"`
|
||||
ResultExperience int `json:"result_experience"`
|
||||
Account Account `json:"account"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
23
pkg/authkit/models/statuses.go
Normal file
23
pkg/authkit/models/statuses.go
Normal file
@ -0,0 +1,23 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type StatusAttitude = uint8
|
||||
|
||||
const (
|
||||
AttitudeNeutral = StatusAttitude(iota)
|
||||
AttitudePositive
|
||||
AttitudeNegative
|
||||
)
|
||||
|
||||
type Status struct {
|
||||
BaseModel
|
||||
|
||||
Type string `json:"type"`
|
||||
Label string `json:"label"`
|
||||
Attitude StatusAttitude `json:"attitude"`
|
||||
IsNoDisturb bool `json:"is_no_disturb"`
|
||||
IsInvisible bool `json:"is_invisible"`
|
||||
ClearAt *time.Time `json:"clear_at"`
|
||||
AccountID uint `json:"account_id"`
|
||||
}
|
21
pkg/authkit/models/tokens.go
Normal file
21
pkg/authkit/models/tokens.go
Normal file
@ -0,0 +1,21 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type MagicTokenType = int8
|
||||
|
||||
const (
|
||||
ConfirmMagicToken = MagicTokenType(iota)
|
||||
RegistrationMagicToken
|
||||
ResetPasswordMagicToken
|
||||
DeleteAccountMagicToken
|
||||
)
|
||||
|
||||
type MagicToken struct {
|
||||
BaseModel
|
||||
|
||||
Code string `json:"code"`
|
||||
Type int8 `json:"type"`
|
||||
AccountID *uint `json:"account_id"`
|
||||
ExpiredAt *time.Time `json:"expired_at"`
|
||||
}
|
27
pkg/authkit/parser.go
Normal file
27
pkg/authkit/parser.go
Normal file
@ -0,0 +1,27 @@
|
||||
package authkit
|
||||
|
||||
import (
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/authkit/models"
|
||||
"git.solsynth.dev/hypernet/nexus/pkg/nex/sec"
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// GetAccountFromUserInfo returns the account from the user info
|
||||
// This method will not to query the database, it will parse the token and get the subject of the userinfo token
|
||||
func GetAccountFromUserInfo(info *sec.UserInfo) models.Account {
|
||||
raw, _ := json.Marshal(info.Metadata)
|
||||
|
||||
// We assume the token is signed by the same version of service
|
||||
// So directly read the data out of the metadata
|
||||
var out models.Account
|
||||
_ = json.Unmarshal(raw, &out)
|
||||
return out
|
||||
}
|
||||
|
||||
func ParseAccountMiddleware(c *fiber.Ctx) error {
|
||||
if info, ok := c.Locals("nex_user").(*sec.UserInfo); ok {
|
||||
c.Locals("user", GetAccountFromUserInfo(info))
|
||||
}
|
||||
return c.Next()
|
||||
}
|
Reference in New Issue
Block a user