✨ Basis perm nodes feature
This commit is contained in:
parent
0e89e325d4
commit
7d3b804516
10
.idea/workspace.xml
generated
10
.idea/workspace.xml
generated
@ -4,9 +4,9 @@
|
|||||||
<option name="autoReloadType" value="ALL" />
|
<option name="autoReloadType" value="ALL" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="3fefb2c4-b6f9-466b-a523-53352e8d6f95" name="更改" comment=":bug: Fix key exchange cause echo">
|
<list default="true" id="3fefb2c4-b6f9-466b-a523-53352e8d6f95" name="更改" comment=":sparkles: Basis perm nodes feature">
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/pkg/services/notifications.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/services/notifications.go" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/pkg/server/ws.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/server/ws.go" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@ -139,8 +139,6 @@
|
|||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="VcsManagerConfiguration">
|
<component name="VcsManagerConfiguration">
|
||||||
<MESSAGE value=":sparkles: Sign up & Sign in" />
|
|
||||||
<MESSAGE value=":sparkles: An entire complete sign in user flow" />
|
|
||||||
<MESSAGE value=":sparkles: User center page" />
|
<MESSAGE value=":sparkles: User center page" />
|
||||||
<MESSAGE value=":sparkles: Personalize" />
|
<MESSAGE value=":sparkles: Personalize" />
|
||||||
<MESSAGE value=":sparkles: OAuth" />
|
<MESSAGE value=":sparkles: OAuth" />
|
||||||
@ -164,7 +162,9 @@
|
|||||||
<MESSAGE value=":sparkles: E2EE Key Exchange" />
|
<MESSAGE value=":sparkles: E2EE Key Exchange" />
|
||||||
<MESSAGE value=":bug: Bug fixes on E2EE" />
|
<MESSAGE value=":bug: Bug fixes on E2EE" />
|
||||||
<MESSAGE value=":bug: Fix key exchange cause echo" />
|
<MESSAGE value=":bug: Fix key exchange cause echo" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value=":bug: Fix key exchange cause echo" />
|
<MESSAGE value=":bug: Fix notification push issue" />
|
||||||
|
<MESSAGE value=":sparkles: Basis perm nodes feature" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value=":sparkles: Basis perm nodes feature" />
|
||||||
</component>
|
</component>
|
||||||
<component name="VgoProject">
|
<component name="VgoProject">
|
||||||
<settings-migrated>true</settings-migrated>
|
<settings-migrated>true</settings-migrated>
|
||||||
|
@ -3,6 +3,7 @@ package grpc
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/passport/pkg/grpc/proto"
|
"git.solsynth.dev/hydrogen/passport/pkg/grpc/proto"
|
||||||
"git.solsynth.dev/hydrogen/passport/pkg/services"
|
"git.solsynth.dev/hydrogen/passport/pkg/services"
|
||||||
@ -10,16 +11,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (v *Server) Authenticate(_ context.Context, in *proto.AuthRequest) (*proto.AuthReply, error) {
|
func (v *Server) Authenticate(_ context.Context, in *proto.AuthRequest) (*proto.AuthReply, error) {
|
||||||
user, atk, rtk, err := services.Authenticate(in.GetAccessToken(), in.GetRefreshToken(), 0)
|
user, perms, atk, rtk, err := services.Authenticate(in.GetAccessToken(), in.GetRefreshToken(), 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &proto.AuthReply{
|
return &proto.AuthReply{
|
||||||
IsValid: false,
|
IsValid: false,
|
||||||
}, nil
|
}, nil
|
||||||
} else {
|
} else {
|
||||||
|
rawPerms, _ := jsoniter.Marshal(perms)
|
||||||
return &proto.AuthReply{
|
return &proto.AuthReply{
|
||||||
IsValid: true,
|
IsValid: true,
|
||||||
AccessToken: &atk,
|
AccessToken: &atk,
|
||||||
RefreshToken: &rtk,
|
RefreshToken: &rtk,
|
||||||
|
Permissions: rawPerms,
|
||||||
Userinfo: &proto.Userinfo{
|
Userinfo: &proto.Userinfo{
|
||||||
Id: uint64(user.ID),
|
Id: uint64(user.ID),
|
||||||
Name: user.Name,
|
Name: user.Name,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.33.0
|
// protoc-gen-go v1.33.0
|
||||||
// protoc v4.25.3
|
// protoc v5.26.1
|
||||||
// source: auth.proto
|
// source: auth.proto
|
||||||
|
|
||||||
package proto
|
package proto
|
||||||
@ -179,6 +179,7 @@ type AuthReply struct {
|
|||||||
AccessToken *string `protobuf:"bytes,2,opt,name=access_token,json=accessToken,proto3,oneof" json:"access_token,omitempty"`
|
AccessToken *string `protobuf:"bytes,2,opt,name=access_token,json=accessToken,proto3,oneof" json:"access_token,omitempty"`
|
||||||
RefreshToken *string `protobuf:"bytes,3,opt,name=refresh_token,json=refreshToken,proto3,oneof" json:"refresh_token,omitempty"`
|
RefreshToken *string `protobuf:"bytes,3,opt,name=refresh_token,json=refreshToken,proto3,oneof" json:"refresh_token,omitempty"`
|
||||||
Userinfo *Userinfo `protobuf:"bytes,4,opt,name=userinfo,proto3,oneof" json:"userinfo,omitempty"`
|
Userinfo *Userinfo `protobuf:"bytes,4,opt,name=userinfo,proto3,oneof" json:"userinfo,omitempty"`
|
||||||
|
Permissions []byte `protobuf:"bytes,5,opt,name=permissions,proto3,oneof" json:"permissions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AuthReply) Reset() {
|
func (x *AuthReply) Reset() {
|
||||||
@ -241,6 +242,13 @@ func (x *AuthReply) GetUserinfo() *Userinfo {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *AuthReply) GetPermissions() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Permissions
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var File_auth_proto protoreflect.FileDescriptor
|
var File_auth_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_auth_proto_rawDesc = []byte{
|
var file_auth_proto_rawDesc = []byte{
|
||||||
@ -264,7 +272,7 @@ var file_auth_proto_rawDesc = []byte{
|
|||||||
0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00,
|
0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00,
|
||||||
0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x88, 0x01,
|
0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x88, 0x01,
|
||||||
0x01, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f,
|
0x01, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f,
|
||||||
0x6b, 0x65, 0x6e, 0x22, 0xda, 0x01, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6c,
|
0x6b, 0x65, 0x6e, 0x22, 0x91, 0x02, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6c,
|
||||||
0x79, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01, 0x20,
|
0x79, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||||
0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x0c,
|
0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x0c,
|
||||||
0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01,
|
0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01,
|
||||||
@ -275,15 +283,18 @@ var file_auth_proto_rawDesc = []byte{
|
|||||||
0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
|
0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
|
||||||
0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66,
|
0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66,
|
||||||
0x6f, 0x48, 0x02, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x88, 0x01, 0x01,
|
0x6f, 0x48, 0x02, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x88, 0x01, 0x01,
|
||||||
0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65,
|
0x12, 0x25, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18,
|
||||||
0x6e, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f,
|
0x05, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x03, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73,
|
||||||
0x6b, 0x65, 0x6e, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f,
|
0x69, 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x61, 0x63, 0x63, 0x65,
|
||||||
0x32, 0x3e, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x36, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68,
|
0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x72, 0x65, 0x66,
|
||||||
0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x75,
|
||||||
0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x70,
|
0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x70, 0x65, 0x72, 0x6d,
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00,
|
0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0x3e, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12,
|
||||||
0x42, 0x09, 0x5a, 0x07, 0x2e, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
0x36, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12,
|
||||||
0x74, 0x6f, 0x33,
|
0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75,
|
||||||
|
0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x75, 0x74, 0x68,
|
||||||
|
0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x3b, 0x70, 0x72, 0x6f,
|
||||||
|
0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -28,4 +28,5 @@ message AuthReply {
|
|||||||
optional string access_token = 2;
|
optional string access_token = 2;
|
||||||
optional string refresh_token = 3;
|
optional string refresh_token = 3;
|
||||||
optional Userinfo userinfo = 4;
|
optional Userinfo userinfo = 4;
|
||||||
|
optional bytes permissions = 5;
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.3.0
|
// - protoc-gen-go-grpc v1.3.0
|
||||||
// - protoc v4.25.3
|
// - protoc v5.26.1
|
||||||
// source: auth.proto
|
// source: auth.proto
|
||||||
|
|
||||||
package proto
|
package proto
|
||||||
|
@ -6,18 +6,19 @@ import (
|
|||||||
|
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
"gorm.io/datatypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
|
|
||||||
Name string `json:"name" gorm:"uniqueIndex"`
|
Name string `json:"name" gorm:"uniqueIndex"`
|
||||||
Nick string `json:"nick"`
|
Nick string `json:"nick"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Avatar string `json:"avatar"`
|
Avatar string `json:"avatar"`
|
||||||
Banner string `json:"banner"`
|
Banner string `json:"banner"`
|
||||||
ConfirmedAt *time.Time `json:"confirmed_at"`
|
ConfirmedAt *time.Time `json:"confirmed_at"`
|
||||||
PowerLevel int `json:"power_level"`
|
PermNodes datatypes.JSONMap `json:"perm_nodes"`
|
||||||
|
|
||||||
Profile AccountProfile `json:"profile"`
|
Profile AccountProfile `json:"profile"`
|
||||||
PersonalPage AccountPage `json:"personal_page"`
|
PersonalPage AccountPage `json:"personal_page"`
|
||||||
|
@ -42,10 +42,11 @@ func authFunc(c *fiber.Ctx, overrides ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rtk := c.Cookies(services.CookieRefreshKey)
|
rtk := c.Cookies(services.CookieRefreshKey)
|
||||||
if user, atk, rtk, err := services.Authenticate(token, rtk, 0); err == nil {
|
if user, perms, atk, rtk, err := services.Authenticate(token, rtk, 0); err == nil {
|
||||||
if atk != token {
|
if atk != token {
|
||||||
services.SetJwtCookieSet(c, atk, rtk)
|
services.SetJwtCookieSet(c, atk, rtk)
|
||||||
}
|
}
|
||||||
|
c.Locals("permissions", perms)
|
||||||
c.Locals("principal", user)
|
c.Locals("principal", user)
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
|
@ -42,6 +42,7 @@ func listenWebsocket(c *websocket.Conn) {
|
|||||||
var req struct {
|
var req struct {
|
||||||
RequestID string `json:"request_id"`
|
RequestID string `json:"request_id"`
|
||||||
KeypairID string `json:"keypair_id"`
|
KeypairID string `json:"keypair_id"`
|
||||||
|
Algorithm string `json:"algorithm"`
|
||||||
OwnerID uint `json:"owner_id"`
|
OwnerID uint `json:"owner_id"`
|
||||||
Deadline int64 `json:"deadline"`
|
Deadline int64 `json:"deadline"`
|
||||||
}
|
}
|
||||||
@ -49,11 +50,12 @@ func listenWebsocket(c *websocket.Conn) {
|
|||||||
if len(req.RequestID) <= 0 || len(req.KeypairID) <= 0 || req.OwnerID <= 0 {
|
if len(req.RequestID) <= 0 || len(req.KeypairID) <= 0 || req.OwnerID <= 0 {
|
||||||
message = lo.ToPtr(models.UnifiedCommandFromError(fmt.Errorf("invalid request")))
|
message = lo.ToPtr(models.UnifiedCommandFromError(fmt.Errorf("invalid request")))
|
||||||
}
|
}
|
||||||
services.KexRequest(c, req.RequestID, req.KeypairID, req.OwnerID, req.Deadline)
|
services.KexRequest(c, req.RequestID, req.KeypairID, req.Algorithm, req.OwnerID, req.Deadline)
|
||||||
case "kex.provide":
|
case "kex.provide":
|
||||||
var req struct {
|
var req struct {
|
||||||
RequestID string `json:"request_id"`
|
RequestID string `json:"request_id"`
|
||||||
KeypairID string `json:"keypair_id"`
|
KeypairID string `json:"keypair_id"`
|
||||||
|
Algorithm string `json:"algorithm"`
|
||||||
PublicKey []byte `json:"public_key"`
|
PublicKey []byte `json:"public_key"`
|
||||||
}
|
}
|
||||||
_ = jsoniter.Unmarshal(payload, &req)
|
_ = jsoniter.Unmarshal(payload, &req)
|
||||||
|
@ -2,6 +2,8 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"gorm.io/datatypes"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
||||||
@ -66,7 +68,7 @@ func CreateAccount(name, nick, email, password string) (models.Account, error) {
|
|||||||
VerifiedAt: nil,
|
VerifiedAt: nil,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PowerLevel: 0,
|
PermNodes: datatypes.JSONMap(viper.GetStringMap("permissions.default")),
|
||||||
ConfirmedAt: nil,
|
ConfirmedAt: nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +100,14 @@ func ConfirmAccount(code string) error {
|
|||||||
|
|
||||||
return database.C.Transaction(func(tx *gorm.DB) error {
|
return database.C.Transaction(func(tx *gorm.DB) error {
|
||||||
user.ConfirmedAt = lo.ToPtr(time.Now())
|
user.ConfirmedAt = lo.ToPtr(time.Now())
|
||||||
user.PowerLevel += 5
|
|
||||||
|
for k, v := range viper.GetStringMap("permissions.verified") {
|
||||||
|
if val, ok := user.PermNodes[k]; !ok {
|
||||||
|
user.PermNodes[k] = v
|
||||||
|
} else if !HasPermNode(val, v) {
|
||||||
|
user.PermNodes[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := database.C.Delete(&token).Error; err != nil {
|
if err := database.C.Delete(&token).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
const authContextBucket = "AuthContext"
|
const authContextBucket = "AuthContext"
|
||||||
|
|
||||||
func Authenticate(access, refresh string, depth int) (user models.Account, newAccess, newRefresh string, err error) {
|
func Authenticate(access, refresh string, depth int) (user models.Account, perms map[string]any, newAccess, newRefresh string, err error) {
|
||||||
var claims PayloadClaims
|
var claims PayloadClaims
|
||||||
claims, err = DecodeJwt(access)
|
claims, err = DecodeJwt(access)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -37,6 +37,7 @@ func Authenticate(access, refresh string, depth int) (user models.Account, newAc
|
|||||||
ctx, lookupErr := GetAuthContext(claims.ID)
|
ctx, lookupErr := GetAuthContext(claims.ID)
|
||||||
if lookupErr == nil {
|
if lookupErr == nil {
|
||||||
log.Debug().Str("jti", claims.ID).Msg("Hit auth context cache once!")
|
log.Debug().Str("jti", claims.ID).Msg("Hit auth context cache once!")
|
||||||
|
perms = FilterPermNodes(ctx.Account.PermNodes, ctx.Ticket.Claims)
|
||||||
user = ctx.Account
|
user = ctx.Account
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -44,6 +45,7 @@ func Authenticate(access, refresh string, depth int) (user models.Account, newAc
|
|||||||
ctx, err = GrantAuthContext(claims.ID)
|
ctx, err = GrantAuthContext(claims.ID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Debug().Str("jti", claims.ID).Err(lookupErr).Msg("Missed auth context cache once!")
|
log.Debug().Str("jti", claims.ID).Err(lookupErr).Msg("Missed auth context cache once!")
|
||||||
|
perms = FilterPermNodes(ctx.Account.PermNodes, ctx.Ticket.Claims)
|
||||||
user = ctx.Account
|
user = ctx.Account
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -97,7 +99,7 @@ func GrantAuthContext(jti string) (models.AuthContext, error) {
|
|||||||
return ctx, fmt.Errorf("invalid account: %v", err)
|
return ctx, fmt.Errorf("invalid account: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Every context should expires in some while
|
// Every context should expire in some while
|
||||||
// Once user update their account info, this will have delay to update
|
// Once user update their account info, this will have delay to update
|
||||||
ctx = models.AuthContext{
|
ctx = models.AuthContext{
|
||||||
Ticket: ticket,
|
Ticket: ticket,
|
||||||
|
@ -15,7 +15,7 @@ type kexRequest struct {
|
|||||||
|
|
||||||
var kexRequests = make(map[string]map[string]kexRequest)
|
var kexRequests = make(map[string]map[string]kexRequest)
|
||||||
|
|
||||||
func KexRequest(conn *websocket.Conn, requestId, keypairId string, ownerId uint, deadline int64) {
|
func KexRequest(conn *websocket.Conn, requestId, keypairId, algorithm string, ownerId uint, deadline int64) {
|
||||||
if kexRequests[keypairId] == nil {
|
if kexRequests[keypairId] == nil {
|
||||||
kexRequests[keypairId] = make(map[string]kexRequest)
|
kexRequests[keypairId] = make(map[string]kexRequest)
|
||||||
}
|
}
|
||||||
@ -38,6 +38,7 @@ func KexRequest(conn *websocket.Conn, requestId, keypairId string, ownerId uint,
|
|||||||
Payload: fiber.Map{
|
Payload: fiber.Map{
|
||||||
"request_id": requestId,
|
"request_id": requestId,
|
||||||
"keypair_id": keypairId,
|
"keypair_id": keypairId,
|
||||||
|
"algorithm": algorithm,
|
||||||
"owner_id": ownerId,
|
"owner_id": ownerId,
|
||||||
"deadline": deadline,
|
"deadline": deadline,
|
||||||
},
|
},
|
||||||
|
55
pkg/services/perms.go
Normal file
55
pkg/services/perms.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HasPermNode(held any, required any) bool {
|
||||||
|
heldValue := reflect.ValueOf(held)
|
||||||
|
requiredValue := reflect.ValueOf(required)
|
||||||
|
|
||||||
|
switch heldValue.Kind() {
|
||||||
|
case reflect.Int, reflect.Float64:
|
||||||
|
if heldValue.Float() >= requiredValue.Float() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
if heldValue.String() == requiredValue.String() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
for i := 0; i < heldValue.Len(); i++ {
|
||||||
|
if reflect.DeepEqual(heldValue.Index(i).Interface(), required) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if reflect.DeepEqual(held, required) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func FilterPermNodes(tree map[string]any, claims []string) map[string]any {
|
||||||
|
filteredTree := make(map[string]any)
|
||||||
|
|
||||||
|
match := func(claim, permission string) bool {
|
||||||
|
regex := strings.Replace(permission, "*", ".*", -1)
|
||||||
|
match, _ := regexp.MatchString("^"+regex+"$", claim)
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, claim := range claims {
|
||||||
|
for key, value := range tree {
|
||||||
|
if match(claim, key) {
|
||||||
|
filteredTree[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredTree
|
||||||
|
}
|
@ -35,3 +35,9 @@ refresh_token_duration = 2592000
|
|||||||
dsn = "host=localhost dbname=hy_passport port=5432 sslmode=disable"
|
dsn = "host=localhost dbname=hy_passport port=5432 sslmode=disable"
|
||||||
prefix = "passport_"
|
prefix = "passport_"
|
||||||
bolt = "uploads/bolt.db"
|
bolt = "uploads/bolt.db"
|
||||||
|
|
||||||
|
[permissions.default]
|
||||||
|
CreatePaperclipAttachments = 1048576
|
||||||
|
|
||||||
|
[permissions.verified]
|
||||||
|
CreatePaperclipAttachments = 26214400
|
Loading…
Reference in New Issue
Block a user