feat: plugin-declared member token scopes (pact.HasFrontendTokenScopes)
- CompileAPITokenScopes builds the catalog from the built-ins and the activated plugins' declarations; a bad name, a redeclared built-in, a duplicate, an empty label or a missing phrase key fails boot - POST /tokens, user:token:create and MintAPITokenFor check the application's own catalog (422 text unchanged); MintAPIToken keeps its signature with a process-wide fallback for declared scopes - GET /_user/api/v1/tokens/scopes lists the built-ins and the declared scopes with translated labels - built-in scope labels in en and pl; TestMemberTokenScopesSmoke
This commit is contained in:
29
plugin.go
29
plugin.go
@@ -21,6 +21,7 @@ import (
|
||||
"git.golem15.com/golem15/summercms/modules/lagoon"
|
||||
"git.golem15.com/golem15/summercms/modules/pact"
|
||||
"git.golem15.com/golem15/summercms/modules/party"
|
||||
"git.golem15.com/golem15/summercms/modules/phrasebook"
|
||||
"git.golem15.com/golem15/summercms/modules/surf"
|
||||
"github.com/go-gormigrate/gormigrate/v2"
|
||||
"gorm.io/gorm"
|
||||
@@ -110,12 +111,40 @@ func (p *Plugin) Boot(app *backpack.App) error {
|
||||
if err := p.bootBackendLinks(app); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.bootAPITokenScopes(app); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.bootMCPGuard(app); err != nil {
|
||||
return err
|
||||
}
|
||||
return classes.RegisterUserAuthorizer(app)
|
||||
}
|
||||
|
||||
// bootAPITokenScopes compiles the member token scope catalog from the
|
||||
// activated plugins (pact.HasFrontendTokenScopes), checks that every phrase
|
||||
// key it names exists, and publishes it. A bad declaration fails boot.
|
||||
func (p *Plugin) bootAPITokenScopes(app *backpack.App) error {
|
||||
activated, _ := app.Lookup[party.Activated]()
|
||||
catalog, err := classes.CompileAPITokenScopes(activated)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tr, ok := app.Lookup[*phrasebook.Translator](); ok && tr != nil {
|
||||
for _, scope := range catalog.Scopes() {
|
||||
for _, text := range []string{scope.Label, scope.Description} {
|
||||
if strings.Contains(text, "::") && !tr.Has(text) {
|
||||
who := scope.PluginID
|
||||
if who == "" {
|
||||
who = "golem15.user"
|
||||
}
|
||||
return fmt.Errorf("golem15.user: member token scope %s (%s) names missing phrase key %s", scope.Name, who, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return app.Publish(catalog)
|
||||
}
|
||||
|
||||
// bootMCPGuard registers the "user" MCP guard provider in the application's
|
||||
// *pact.MCPGuards (publishing the registry when no one did yet) and
|
||||
// publishes the same value as pact.MCPPersonalTokenResolver for the
|
||||
|
||||
Reference in New Issue
Block a user