1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
package captokens
// TokenDef defines a token type with its required and optional scope fields.
type TokenDef struct {
// RequiredScope lists fields that must be present in the token scope
RequiredScope []string
// OptionalScope lists fields that may be present in the token scope
OptionalScope []string
// Description explains what this token type authorizes
Description string
}
// TokenDefinitions is the registry of all known token types.
// Token IDs follow the pattern: "service:operation"
var TokenDefinitions = map[string]TokenDef{
"maildir:list-mailboxes": {
RequiredScope: []string{"root_dir"},
OptionalScope: []string{},
Description: "List all mailboxes under root_dir",
},
"maildir:open-mailbox": {
RequiredScope: []string{"mailbox_dir"},
OptionalScope: []string{},
Description: "Access to list and search messages in mailbox_dir",
},
"maildir:read-metadata": {
RequiredScope: []string{"mailbox_dir"},
OptionalScope: []string{},
Description: "Read message summaries (from/to/subject/date) in mailbox_dir",
},
"maildir:read-message": {
RequiredScope: []string{"mailbox_dir"},
OptionalScope: []string{"message_id"}, // can restrict to specific message
Description: "Read full message content in mailbox_dir",
},
"maildir:search-mailbox": {
RequiredScope: []string{"mailbox_dir"},
OptionalScope: []string{},
Description: "Search messages in mailbox_dir",
},
}
// ValidateTokenType checks if a token ID exists in the registry.
func ValidateTokenType(tokenID string) (TokenDef, bool) {
def, exists := TokenDefinitions[tokenID]
return def, exists
}
// ValidateScope checks if a scope map contains all required fields for a token type.
// Returns error if required fields are missing.
func ValidateScope(tokenID string, scope map[string]any) error {
def, exists := TokenDefinitions[tokenID]
if !exists {
return &UnknownTokenTypeError{TokenID: tokenID}
}
// Check all required fields are present
for _, field := range def.RequiredScope {
if _, ok := scope[field]; !ok {
return &MissingScopeFieldError{
TokenID: tokenID,
Field: field,
}
}
}
return nil
}
// UnknownTokenTypeError is returned when a token ID is not in the registry.
type UnknownTokenTypeError struct {
TokenID string
}
func (e *UnknownTokenTypeError) Error() string {
return "unknown token type: " + e.TokenID
}
// MissingScopeFieldError is returned when required scope fields are missing.
type MissingScopeFieldError struct {
TokenID string
Field string
}
func (e *MissingScopeFieldError) Error() string {
return "token " + e.TokenID + " requires scope field: " + e.Field
}
|