Documentation
¶
Overview ¶
Package services provides optimized token services with compression and stateless scope management
Index ¶
- Constants
- Variables
- func GenerateKey() ([]byte, error)
- func GetScopeNames(scopeNumbers []int) []string
- func GetScopeNumbers(scopeNames []string) []int
- func KeyFromString(s string) []byte
- func SendEmail(ctx context.Context, _awsConfig aws.Config, req *models.EmailSendRequest) error
- func SendTeamAddEmail(ctx context.Context, _awsConfig aws.Config, req *models.EmailSendRequest) error
- type APIKeyMock
- type ApitoTokenService
- type AuthServiceInterface
- type BrankaToken
- func (t *BrankaToken) GenerateProjectToken(claims *models.TokenClaims, ttl uint32) (*string, error)
- func (t *BrankaToken) GenerateSyncToken(ctx context.Context, userID, payload interface{}, tokenType string, ...) (*string, error)
- func (t *BrankaToken) Validate(ctx context.Context, token string) (*models.TokenClaims, error)
- func (t *BrankaToken) ValidateAndSetContext(c echo.Context, token string) (*models.TokenClaims, error)
- type BrankaTokenOptimized
- func (t *BrankaTokenOptimized) GenerateSyncTokenOptimized(ctx context.Context, userID string, projectIDs []string, scopes []string, ...) (*string, error)
- func (t *BrankaTokenOptimized) GetTokenInfo(token string) (*TokenInfo, error)
- func (t *BrankaTokenOptimized) ValidateSyncTokenAndSetContext(c echo.Context, token string) (*models.TokenClaims, error)
- func (t *BrankaTokenOptimized) ValidateSyncTokenOptimized(ctx context.Context, token string) (*models.TokenClaims, error)
- type CompactSyncPayload
- type CustomResponseWriter
- type CustomToken
- func (ct *CustomToken) DecodeToString(token string) (string, error)
- func (ct *CustomToken) DecodeToStringWithTTL(token string, ttlSeconds uint32) (string, error)
- func (ct *CustomToken) EncodeToString(payload string) (string, error)
- func (ct *CustomToken) GetTokenInfo(token string) (*TokenInfo, error)
- func (ct *CustomToken) SetTTL(ttl uint32)
- type DBMock
- type JWTService
- func (s *JWTService) ChangePassword(ctx context.Context, token, old, new string) error
- func (s *JWTService) ConfirmForgetPassword(ctx context.Context, req *models.RegisterRequest) error
- func (s *JWTService) ConfirmSignup(ctx context.Context, req *models.RegisterRequest) error
- func (t *JWTService) ExchangeAndRefreshToken(ctx context.Context, user *models.SystemUser) (*models.JWTTokens, error)
- func (s *JWTService) ForgetPasswordRequest(ctx context.Context, req *models.RegisterRequest) error
- func (s *JWTService) GenerateIdToken(param *models.CommonSystemParams) (*string, error)
- func (s *JWTService) GenerateLoginAccessToken(ctx context.Context) (*string, error)
- func (s *JWTService) GenerateLoginIDToken(ctx context.Context, projectWithRoles *models.ProjectWithRoles) (*string, error)
- func (s *JWTService) GenerateLoginRefreshToken(projectWithRoles *models.ProjectWithRoles) (*string, error)
- func (s *JWTService) GenerateLoginToken(ctx context.Context, projectWithRoles *models.ProjectWithRoles) (*models.JWTTokens, error)
- func (s *JWTService) GenerateRandomString(n int) string
- func (s *JWTService) GenerateRefreshToken(param *models.CommonSystemParams, month int) (*string, error)
- func (s *JWTService) GetTokenSession(ctx context.Context, email string) (string, error)
- func (s *JWTService) Invalidate(tokenString string) error
- func (s *JWTService) IsInBlacklist(token string) bool
- func (s *JWTService) Login(ctx context.Context, req *models.LoginRequest) (*models.JWTTokens, error)
- func (s *JWTService) Logout(ctx context.Context, token string) error
- func (s *JWTService) Signup(ctx context.Context, req *models.RegisterRequest) error
- func (s *JWTService) StoreTokenSession(ctx context.Context, email string, session string, ttl time.Duration) error
- func (s *JWTService) Validate(tokenObj bool, tokenString string) (bool, error)
- func (s *JWTService) VerifyAccessToken(ctx context.Context, token string) error
- func (s *JWTService) VerifyIDToken(ctx context.Context, token string) (*models.TokenClaims, error)
- type KeyGenMock
- type LocalAuthService
- func (l *LocalAuthService) ChangePassword(ctx context.Context, user *models.SystemUser, old, new string) (*models.SystemUser, error)
- func (l *LocalAuthService) ConfirmForgetPassword(ctx context.Context, req *models.RegisterRequest) error
- func (l *LocalAuthService) ConfirmSignup(ctx context.Context, req *models.RegisterRequest) error
- func (l *LocalAuthService) ExchangeAndRefreshToken(ctx context.Context, projectWithRoles *models.ProjectWithRoles) (*models.JWTTokens, error)
- func (l *LocalAuthService) ForgetPasswordRequest(ctx context.Context, req *models.RegisterRequest) error
- func (l *LocalAuthService) Login(ctx context.Context, req *models.LoginRequest, user *models.SystemUser, ...) (*models.JWTTokens, error)
- func (l *LocalAuthService) Logout(ctx context.Context, token string) error
- func (l *LocalAuthService) Signup(ctx context.Context, registerRequest *models.RegisterRequest) (*models.SystemUser, error)
- func (l *LocalAuthService) VerifyAccessToken(ctx context.Context, token string) error
- func (l *LocalAuthService) VerifyIDToken(ctx context.Context, token string) (*models.TokenClaims, error)
- type ProjectKeyManager
- func (m *ProjectKeyManager) GenerateKey(payload *models.TokenClaims) (string, error)
- func (m *ProjectKeyManager) GenerateTenantToken(ctx context.Context, tenantID, token string) (string, error)
- func (m *ProjectKeyManager) Validate(ctx context.Context, key string, skipDBCheck bool) (*models.TokenClaims, error)
- func (m *ProjectKeyManager) ValidateAndSetContext(c echo.Context, token string) (*models.TokenClaims, error)
- type TokenHeader
- type TokenInfo
- type TokenService
Constants ¶
const ( // System scopes ScopeSystemAPIRead = 1 ScopeSystemAPIWrite = 2 ScopeSystemAdmin = 3 // Project scopes ScopeProjectRead = 10 ScopeProjectWrite = 11 ScopeProjectAdmin = 12 // Plugin scopes ScopePluginRead = 20 ScopePluginWrite = 21 ScopePluginAdmin = 22 // User scopes ScopeUserRead = 30 ScopeUserWrite = 31 ScopeUserAdmin = 32 // Analytics scopes ScopeAnalyticsRead = 40 ScopeAnalyticsWrite = 41 // Sync scopes ScopeSyncRead = 50 ScopeSyncWrite = 51 ScopeSyncAdmin = 52 )
Scope constants - stateless mapping
const ( // Token version - for future compatibility TokenVersion = 1 // Header size: version(1) + timestamp(8) + nonce(12) = 21 bytes HeaderSize = 21 // Nonce size for AES-GCM NonceSize = 12 // HMAC size HMACSize = 32 // Minimum token size MinTokenSize = HeaderSize + NonceSize + HMACSize + 16 // 16 is minimum AES block size )
Custom token implementation constants
const (
CharSet = "UTF-8" // Character Set
)
Variables ¶
var ( ErrInvalidKey = errors.New("invalid key format") ErrExpiredKey = errors.New("key has expired") ErrInvalidPayload = errors.New("invalid payload") )
var ScopeNameToNumber = map[string]int{ "system_api_read": ScopeSystemAPIRead, "system_api_write": ScopeSystemAPIWrite, "system_admin": ScopeSystemAdmin, "project_read": ScopeProjectRead, "project_write": ScopeProjectWrite, "project_admin": ScopeProjectAdmin, "plugin_read": ScopePluginRead, "plugin_write": ScopePluginWrite, "plugin_admin": ScopePluginAdmin, "user_read": ScopeUserRead, "user_write": ScopeUserWrite, "user_admin": ScopeUserAdmin, "analytics_read": ScopeAnalyticsRead, "analytics_write": ScopeAnalyticsWrite, "sync_read": ScopeSyncRead, "sync_write": ScopeSyncWrite, "sync_admin": ScopeSyncAdmin, }
ScopeNameToNumber maps scope names to their numeric representations
var ScopeNumberToName = map[int]string{ ScopeSystemAPIRead: "system_api_read", ScopeSystemAPIWrite: "system_api_write", ScopeSystemAdmin: "system_admin", ScopeProjectRead: "project_read", ScopeProjectWrite: "project_write", ScopeProjectAdmin: "project_admin", ScopePluginRead: "plugin_read", ScopePluginWrite: "plugin_write", ScopePluginAdmin: "plugin_admin", ScopeUserRead: "user_read", ScopeUserWrite: "user_write", ScopeUserAdmin: "user_admin", ScopeAnalyticsRead: "analytics_read", ScopeAnalyticsWrite: "analytics_write", ScopeSyncRead: "sync_read", ScopeSyncWrite: "sync_write", ScopeSyncAdmin: "sync_admin", }
ScopeNumberToName maps numeric scope representations back to their names
Functions ¶
func GenerateKey ¶ added in v1.2.1
GenerateKey generates a random 32-byte key for token encryption
func GetScopeNames ¶ added in v1.2.1
GetScopeNames returns scope names for given numbers (utility function)
func GetScopeNumbers ¶ added in v1.2.1
GetScopeNumbers returns scope numbers for given names (utility function)
func KeyFromString ¶ added in v1.2.1
KeyFromString creates a key from a string (using SHA256)
func SendTeamAddEmail ¶
Types ¶
type APIKeyMock ¶
type APIKeyMock struct {
Val []byte
}
func (APIKeyMock) Value ¶
func (k APIKeyMock) Value() []byte
type ApitoTokenService ¶
type ApitoTokenService struct {
Batch *goBatch.Batch[models.ProjectApiTracking]
// contains filtered or unexported fields
}
func NewApitoTokenService ¶
func NewApitoTokenService(cfg *models.Config, auth AuthServiceInterface, driver interfaces.ApitoSystemDB) (*ApitoTokenService, error)
func (*ApitoTokenService) ApitoPublicFunctionRouteHandler ¶
func (t *ApitoTokenService) ApitoPublicFunctionRouteHandler(next echo.HandlerFunc) echo.HandlerFunc
func (*ApitoTokenService) ApitoTokenHandler ¶
func (t *ApitoTokenService) ApitoTokenHandler(next echo.HandlerFunc) echo.HandlerFunc
func (*ApitoTokenService) Shutdown ¶ added in v1.1.6
func (t *ApitoTokenService) Shutdown() error
Shutdown gracefully stops the batch processor
type AuthServiceInterface ¶
type AuthServiceInterface interface {
Login(ctx context.Context, req *models.LoginRequest, user *models.SystemUser, projectWithRoles *models.ProjectWithRoles) (*models.JWTTokens, error)
Signup(ctx context.Context, req *models.RegisterRequest) (*models.SystemUser, error)
ConfirmSignup(ctx context.Context, req *models.RegisterRequest) error
ForgetPasswordRequest(ctx context.Context, req *models.RegisterRequest) error
ConfirmForgetPassword(ctx context.Context, req *models.RegisterRequest) error
ChangePassword(ctx context.Context, user *models.SystemUser, old, new string) (*models.SystemUser, error)
Logout(ctx context.Context, token string) error
VerifyIDToken(ctx context.Context, token string) (*models.TokenClaims, error)
VerifyAccessToken(ctx context.Context, token string) error
ExchangeAndRefreshToken(ctx context.Context, projectWithRoles *models.ProjectWithRoles) (*models.JWTTokens, error)
}
type BrankaToken ¶
func GetBrankaToken ¶
func GetBrankaToken(cfg *models.Config, db interfaces.ApitoSystemDB) *BrankaToken
func (*BrankaToken) GenerateProjectToken ¶
func (t *BrankaToken) GenerateProjectToken(claims *models.TokenClaims, ttl uint32) (*string, error)
func (*BrankaToken) GenerateSyncToken ¶ added in v1.2.1
func (*BrankaToken) Validate ¶
func (t *BrankaToken) Validate(ctx context.Context, token string) (*models.TokenClaims, error)
func (*BrankaToken) ValidateAndSetContext ¶
func (t *BrankaToken) ValidateAndSetContext(c echo.Context, token string) (*models.TokenClaims, error)
type BrankaTokenOptimized ¶ added in v1.2.1
type BrankaTokenOptimized struct {
Token *CustomToken
// contains filtered or unexported fields
}
BrankaTokenOptimized - optimized token service using our custom token library
func GetBrankaTokenOptimized ¶ added in v1.2.1
func GetBrankaTokenOptimized(cfg *models.Config, db interfaces.ApitoSystemDB) *BrankaTokenOptimized
func (*BrankaTokenOptimized) GenerateSyncTokenOptimized ¶ added in v1.2.1
func (t *BrankaTokenOptimized) GenerateSyncTokenOptimized(ctx context.Context, userID string, projectIDs []string, scopes []string, tokenType string, expireAt int64) (*string, error)
GenerateSyncTokenOptimized creates an optimized sync token with compressed payload
func (*BrankaTokenOptimized) GetTokenInfo ¶ added in v1.2.1
func (t *BrankaTokenOptimized) GetTokenInfo(token string) (*TokenInfo, error)
GetTokenInfo extracts metadata from a token without decrypting the payload
func (*BrankaTokenOptimized) ValidateSyncTokenAndSetContext ¶ added in v1.2.1
func (t *BrankaTokenOptimized) ValidateSyncTokenAndSetContext(c echo.Context, token string) (*models.TokenClaims, error)
ValidateSyncTokenAndSetContext validates token and sets context (optimized version)
func (*BrankaTokenOptimized) ValidateSyncTokenOptimized ¶ added in v1.2.1
func (t *BrankaTokenOptimized) ValidateSyncTokenOptimized(ctx context.Context, token string) (*models.TokenClaims, error)
ValidateSyncTokenOptimized validates an optimized sync token
type CompactSyncPayload ¶ added in v1.2.1
type CompactSyncPayload struct {
PIDs []string `json:"p"` // project_ids (shortened)
SCPs []int `json:"s"` // scopes as numbers (shortened)
}
CompactSyncPayload - optimized payload structure
type CustomResponseWriter ¶
type CustomResponseWriter struct {
http.ResponseWriter
Body *bytes.Buffer
Status int
}
CustomResponseWriter is a wrapper around the standard http.ResponseWriter that captures the status code and response body.
func (*CustomResponseWriter) Header ¶
func (w *CustomResponseWriter) Header() http.Header
Header returns the header map that will be sent by WriteHeader.
func (*CustomResponseWriter) Write ¶
func (w *CustomResponseWriter) Write(b []byte) (int, error)
Write captures the response body and calls the underlying Write.
func (*CustomResponseWriter) WriteHeader ¶
func (w *CustomResponseWriter) WriteHeader(code int)
WriteHeader captures the status code and calls the underlying WriteHeader.
type CustomToken ¶ added in v1.2.1
type CustomToken struct {
// contains filtered or unexported fields
}
CustomToken represents our proprietary token encoder/decoder
func NewCustomToken ¶ added in v1.2.1
func NewCustomToken(key []byte) (*CustomToken, error)
NewCustomToken creates a new token encoder/decoder with the given key
func (*CustomToken) DecodeToString ¶ added in v1.2.1
func (ct *CustomToken) DecodeToString(token string) (string, error)
DecodeToString decodes a proprietary token back to the original payload string
func (*CustomToken) DecodeToStringWithTTL ¶ added in v1.2.1
func (ct *CustomToken) DecodeToStringWithTTL(token string, ttlSeconds uint32) (string, error)
DecodeToStringWithTTL decodes a token and validates TTL
func (*CustomToken) EncodeToString ¶ added in v1.2.1
func (ct *CustomToken) EncodeToString(payload string) (string, error)
EncodeToString encodes a payload string into a proprietary token
func (*CustomToken) GetTokenInfo ¶ added in v1.2.1
func (ct *CustomToken) GetTokenInfo(token string) (*TokenInfo, error)
GetTokenInfo extracts information from a token without decrypting
func (*CustomToken) SetTTL ¶ added in v1.2.1
func (ct *CustomToken) SetTTL(ttl uint32)
SetTTL is a compatibility method (tokens are stateless, TTL is validated on decode)
type DBMock ¶
type DBMock struct {
typederrs.NotFoundErrCheck
ExpInsAPIKErr error
ExpAPIKBUsrIDVal api.Key
ExpAPIKsBUsrIDValErr error
RecInsAPIKUsrID string
}
func (*DBMock) APIKeyByUserIDVal ¶
type JWTService ¶
type JWTService struct {
Cfg *models.Config
PrivateKey *rsa.PrivateKey
PublicKey *rsa.PublicKey
// contains filtered or unexported fields
}
func GetJWTService ¶
func GetJWTService(cfg *models.Config) (*JWTService, error)
func GetJWTServiceWithNoSqlDb ¶
func GetJWTServiceWithNoSqlDb(cfg *models.Config) *JWTService
func GetJWTServiceWithRedis ¶
func GetJWTServiceWithRedis(cfg *models.Config, kvService interfaces.KeyValueServiceInterface) *JWTService
func (*JWTService) ChangePassword ¶
func (s *JWTService) ChangePassword(ctx context.Context, token, old, new string) error
func (*JWTService) ConfirmForgetPassword ¶
func (s *JWTService) ConfirmForgetPassword(ctx context.Context, req *models.RegisterRequest) error
func (*JWTService) ConfirmSignup ¶
func (s *JWTService) ConfirmSignup(ctx context.Context, req *models.RegisterRequest) error
func (*JWTService) ExchangeAndRefreshToken ¶
func (t *JWTService) ExchangeAndRefreshToken(ctx context.Context, user *models.SystemUser) (*models.JWTTokens, error)
no use at this time
func (*JWTService) ForgetPasswordRequest ¶
func (s *JWTService) ForgetPasswordRequest(ctx context.Context, req *models.RegisterRequest) error
func (*JWTService) GenerateIdToken ¶
func (s *JWTService) GenerateIdToken(param *models.CommonSystemParams) (*string, error)
func (*JWTService) GenerateLoginAccessToken ¶
func (s *JWTService) GenerateLoginAccessToken(ctx context.Context) (*string, error)
func (*JWTService) GenerateLoginIDToken ¶
func (s *JWTService) GenerateLoginIDToken(ctx context.Context, projectWithRoles *models.ProjectWithRoles) (*string, error)
func (*JWTService) GenerateLoginRefreshToken ¶
func (s *JWTService) GenerateLoginRefreshToken(projectWithRoles *models.ProjectWithRoles) (*string, error)
func (*JWTService) GenerateLoginToken ¶
func (s *JWTService) GenerateLoginToken(ctx context.Context, projectWithRoles *models.ProjectWithRoles) (*models.JWTTokens, error)
func (*JWTService) GenerateRandomString ¶
func (s *JWTService) GenerateRandomString(n int) string
func (*JWTService) GenerateRefreshToken ¶
func (s *JWTService) GenerateRefreshToken(param *models.CommonSystemParams, month int) (*string, error)
func (*JWTService) GetTokenSession ¶ added in v1.3.0
func (*JWTService) Invalidate ¶
func (s *JWTService) Invalidate(tokenString string) error
func (*JWTService) IsInBlacklist ¶
func (s *JWTService) IsInBlacklist(token string) bool
func (*JWTService) Login ¶
func (s *JWTService) Login(ctx context.Context, req *models.LoginRequest) (*models.JWTTokens, error)
func (*JWTService) Signup ¶
func (s *JWTService) Signup(ctx context.Context, req *models.RegisterRequest) error
func (*JWTService) StoreTokenSession ¶ added in v1.3.0
func (*JWTService) Validate ¶
func (s *JWTService) Validate(tokenObj bool, tokenString string) (bool, error)
func (*JWTService) VerifyAccessToken ¶
func (s *JWTService) VerifyAccessToken(ctx context.Context, token string) error
func (*JWTService) VerifyIDToken ¶
func (s *JWTService) VerifyIDToken(ctx context.Context, token string) (*models.TokenClaims, error)
type KeyGenMock ¶
func (*KeyGenMock) SecureRandomBytes ¶
func (kg *KeyGenMock) SecureRandomBytes(length int) ([]byte, error)
type LocalAuthService ¶
type LocalAuthService struct {
TokenService *JWTService
}
func NewLocalAuthService ¶
func NewLocalAuthService(cfg *models.Config, tokenService *JWTService) (*LocalAuthService, error)
func (*LocalAuthService) ChangePassword ¶
func (l *LocalAuthService) ChangePassword(ctx context.Context, user *models.SystemUser, old, new string) (*models.SystemUser, error)
func (*LocalAuthService) ConfirmForgetPassword ¶
func (l *LocalAuthService) ConfirmForgetPassword(ctx context.Context, req *models.RegisterRequest) error
func (*LocalAuthService) ConfirmSignup ¶
func (l *LocalAuthService) ConfirmSignup(ctx context.Context, req *models.RegisterRequest) error
func (*LocalAuthService) ExchangeAndRefreshToken ¶
func (l *LocalAuthService) ExchangeAndRefreshToken(ctx context.Context, projectWithRoles *models.ProjectWithRoles) (*models.JWTTokens, error)
func (*LocalAuthService) ForgetPasswordRequest ¶
func (l *LocalAuthService) ForgetPasswordRequest(ctx context.Context, req *models.RegisterRequest) error
func (*LocalAuthService) Login ¶
func (l *LocalAuthService) Login(ctx context.Context, req *models.LoginRequest, user *models.SystemUser, projectWithRoles *models.ProjectWithRoles) (*models.JWTTokens, error)
func (*LocalAuthService) Logout ¶
func (l *LocalAuthService) Logout(ctx context.Context, token string) error
func (*LocalAuthService) Signup ¶
func (l *LocalAuthService) Signup(ctx context.Context, registerRequest *models.RegisterRequest) (*models.SystemUser, error)
func (*LocalAuthService) VerifyAccessToken ¶
func (l *LocalAuthService) VerifyAccessToken(ctx context.Context, token string) error
func (*LocalAuthService) VerifyIDToken ¶
func (l *LocalAuthService) VerifyIDToken(ctx context.Context, token string) (*models.TokenClaims, error)
type ProjectKeyManager ¶ added in v1.2.1
type ProjectKeyManager struct {
// contains filtered or unexported fields
}
ProjectKeyManager handles API key operations with optimized performance
func NewProjectKeyManager ¶ added in v1.2.1
func NewProjectKeyManager(cfg *models.Config, driver interfaces.ApitoSystemDB) (*ProjectKeyManager, error)
func NewProjectKeyManagerNoDB ¶ added in v1.2.1
func NewProjectKeyManagerNoDB(cfg *models.Config) (*ProjectKeyManager, error)
func (*ProjectKeyManager) GenerateKey ¶ added in v1.2.1
func (m *ProjectKeyManager) GenerateKey(payload *models.TokenClaims) (string, error)
func (*ProjectKeyManager) GenerateTenantToken ¶ added in v1.2.1
func (*ProjectKeyManager) Validate ¶ added in v1.2.1
func (m *ProjectKeyManager) Validate(ctx context.Context, key string, skipDBCheck bool) (*models.TokenClaims, error)
func (*ProjectKeyManager) ValidateAndSetContext ¶ added in v1.2.1
func (m *ProjectKeyManager) ValidateAndSetContext(c echo.Context, token string) (*models.TokenClaims, error)
type TokenHeader ¶ added in v1.2.1
type TokenHeader struct {
Version uint8 // Token version (1 byte)
Timestamp int64 // Unix timestamp (8 bytes)
Nonce []byte // Random nonce (12 bytes)
}
TokenHeader represents the token header structure
type TokenInfo ¶ added in v1.2.1
type TokenInfo struct {
Version uint8 `json:"version"`
Timestamp int64 `json:"timestamp"`
CreatedAt time.Time `json:"created_at"`
Size int `json:"size"`
}
TokenInfo contains metadata about a token
type TokenService ¶
func GetTokenService ¶
func GetTokenService(cfg *models.Config) *TokenService
func GetTokenServiceWithRedis ¶
func GetTokenServiceWithRedis(cfg *models.Config) *TokenService
func (*TokenService) GenerateProjectToken ¶
func (t *TokenService) GenerateProjectToken(user *models.SystemUser, projectId string) (string, error)
func (*TokenService) Validate ¶
func (t *TokenService) Validate(cfg *models.Config, token string) (*models.TokenClaims, error)
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package plugin provides functionality for loading and managing HashiCorp plugins from individual config.yml files in plugin directories.
|
Package plugin provides functionality for loading and managing HashiCorp plugins from individual config.yml files in plugin directories. |