mirror of
https://github.com/safing/portmaster
synced 2025-09-02 02:29:12 +00:00
* Move portbase into monorepo * Add new simple module mgr * [WIP] Switch to new simple module mgr * Add StateMgr and more worker variants * [WIP] Switch more modules * [WIP] Switch more modules * [WIP] swtich more modules * [WIP] switch all SPN modules * [WIP] switch all service modules * [WIP] Convert all workers to the new module system * [WIP] add new task system to module manager * [WIP] Add second take for scheduling workers * [WIP] Add FIXME for bugs in new scheduler * [WIP] Add minor improvements to scheduler * [WIP] Add new worker scheduler * [WIP] Fix more bug related to new module system * [WIP] Fix start handing of the new module system * [WIP] Improve startup process * [WIP] Fix minor issues * [WIP] Fix missing subsystem in settings * [WIP] Initialize managers in constructor * [WIP] Move module event initialization to constrictors * [WIP] Fix setting for enabling and disabling the SPN module * [WIP] Move API registeration into module construction * [WIP] Update states mgr for all modules * [WIP] Add CmdLine operation support * Add state helper methods to module group and instance * Add notification and module status handling to status package * Fix starting issues * Remove pilot widget and update security lock to new status data * Remove debug logs * Improve http server shutdown * Add workaround for cleanly shutting down firewall+netquery * Improve logging * Add syncing states with notifications for new module system * Improve starting, stopping, shutdown; resolve FIXMEs/TODOs * [WIP] Fix most unit tests * Review new module system and fix minor issues * Push shutdown and restart events again via API * Set sleep mode via interface * Update example/template module * [WIP] Fix spn/cabin unit test * Remove deprecated UI elements * Make log output more similar for the logging transition phase * Switch spn hub and observer cmds to new module system * Fix log sources * Make worker mgr less error prone * Fix tests and minor issues * Fix observation hub * Improve shutdown and restart handling * Split up big connection.go source file * Move varint and dsd packages to structures repo * Improve expansion test * Fix linter warnings * Fix interception module on windows * Fix linter errors --------- Co-authored-by: Vladimir Stoilov <vladimir@safing.io>
240 lines
5.5 KiB
Go
240 lines
5.5 KiB
Go
package token
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/mr-tron/base58"
|
|
|
|
"github.com/safing/jess/lhash"
|
|
"github.com/safing/structures/dsd"
|
|
)
|
|
|
|
const (
|
|
scrambleSecretSize = 32
|
|
)
|
|
|
|
// ScrambleToken is token based on hashing.
|
|
type ScrambleToken struct {
|
|
Token []byte
|
|
}
|
|
|
|
// Pack packs the token.
|
|
func (pbt *ScrambleToken) Pack() ([]byte, error) {
|
|
return pbt.Token, nil
|
|
}
|
|
|
|
// UnpackScrambleToken unpacks the token.
|
|
func UnpackScrambleToken(token []byte) (*ScrambleToken, error) {
|
|
return &ScrambleToken{Token: token}, nil
|
|
}
|
|
|
|
// ScrambleHandler is a handler for the scramble tokens.
|
|
type ScrambleHandler struct {
|
|
sync.Mutex
|
|
opts *ScrambleOptions
|
|
|
|
storageLock sync.Mutex
|
|
Storage []*ScrambleToken
|
|
|
|
verifiersLock sync.RWMutex
|
|
verifiers map[string]*ScrambleToken
|
|
}
|
|
|
|
// ScrambleOptions are options for the ScrambleHandler.
|
|
type ScrambleOptions struct {
|
|
Zone string
|
|
Algorithm lhash.Algorithm
|
|
InitialTokens []string
|
|
InitialVerifiers []string
|
|
Fallback bool
|
|
}
|
|
|
|
// ScrambleTokenRequest is a token request.
|
|
type ScrambleTokenRequest struct{}
|
|
|
|
// IssuedScrambleTokens are issued scrambled tokens.
|
|
type IssuedScrambleTokens struct {
|
|
Tokens []*ScrambleToken
|
|
}
|
|
|
|
// NewScrambleHandler creates a new scramble handler.
|
|
func NewScrambleHandler(opts ScrambleOptions) (*ScrambleHandler, error) {
|
|
sh := &ScrambleHandler{
|
|
opts: &opts,
|
|
verifiers: make(map[string]*ScrambleToken, len(opts.InitialTokens)+len(opts.InitialVerifiers)),
|
|
}
|
|
|
|
// Add initial tokens.
|
|
sh.Storage = make([]*ScrambleToken, len(opts.InitialTokens))
|
|
for i, token := range opts.InitialTokens {
|
|
// Add to storage.
|
|
tokenData, err := base58.Decode(token)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decode initial token %q: %w", token, err)
|
|
}
|
|
sh.Storage[i] = &ScrambleToken{
|
|
Token: tokenData,
|
|
}
|
|
|
|
// Add to verifiers.
|
|
scrambledToken := lhash.Digest(sh.opts.Algorithm, tokenData).Bytes()
|
|
sh.verifiers[string(scrambledToken)] = sh.Storage[i]
|
|
}
|
|
|
|
// Add initial verifiers.
|
|
for _, verifier := range opts.InitialVerifiers {
|
|
verifierData, err := base58.Decode(verifier)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decode verifier %q: %w", verifier, err)
|
|
}
|
|
sh.verifiers[string(verifierData)] = &ScrambleToken{}
|
|
}
|
|
|
|
return sh, nil
|
|
}
|
|
|
|
// Zone returns the zone name.
|
|
func (sh *ScrambleHandler) Zone() string {
|
|
return sh.opts.Zone
|
|
}
|
|
|
|
// ShouldRequest returns whether the new tokens should be requested.
|
|
func (sh *ScrambleHandler) ShouldRequest() bool {
|
|
sh.storageLock.Lock()
|
|
defer sh.storageLock.Unlock()
|
|
|
|
return len(sh.Storage) == 0
|
|
}
|
|
|
|
// Amount returns the current amount of tokens in this handler.
|
|
func (sh *ScrambleHandler) Amount() int {
|
|
sh.storageLock.Lock()
|
|
defer sh.storageLock.Unlock()
|
|
|
|
return len(sh.Storage)
|
|
}
|
|
|
|
// IsFallback returns whether this handler should only be used as a fallback.
|
|
func (sh *ScrambleHandler) IsFallback() bool {
|
|
return sh.opts.Fallback
|
|
}
|
|
|
|
// CreateTokenRequest creates a token request to be sent to the token server.
|
|
func (sh *ScrambleHandler) CreateTokenRequest() (request *ScrambleTokenRequest) {
|
|
return &ScrambleTokenRequest{}
|
|
}
|
|
|
|
// IssueTokens sign the requested tokens.
|
|
func (sh *ScrambleHandler) IssueTokens(request *ScrambleTokenRequest) (response *IssuedScrambleTokens, err error) {
|
|
// Copy the storage.
|
|
tokens := make([]*ScrambleToken, len(sh.Storage))
|
|
copy(tokens, sh.Storage)
|
|
|
|
return &IssuedScrambleTokens{
|
|
Tokens: tokens,
|
|
}, nil
|
|
}
|
|
|
|
// ProcessIssuedTokens processes the issued token from the server.
|
|
func (sh *ScrambleHandler) ProcessIssuedTokens(issuedTokens *IssuedScrambleTokens) error {
|
|
sh.verifiersLock.RLock()
|
|
defer sh.verifiersLock.RUnlock()
|
|
|
|
// Validate tokens.
|
|
for i, newToken := range issuedTokens.Tokens {
|
|
// Scramle token.
|
|
scrambledToken := lhash.Digest(sh.opts.Algorithm, newToken.Token).Bytes()
|
|
|
|
// Check if token is valid.
|
|
_, ok := sh.verifiers[string(scrambledToken)]
|
|
if !ok {
|
|
return fmt.Errorf("invalid token on #%d", i)
|
|
}
|
|
}
|
|
|
|
// Copy to storage.
|
|
sh.Storage = issuedTokens.Tokens
|
|
|
|
return nil
|
|
}
|
|
|
|
// Verify verifies the given token.
|
|
func (sh *ScrambleHandler) Verify(token *Token) error {
|
|
if token.Zone != sh.opts.Zone {
|
|
return ErrZoneMismatch
|
|
}
|
|
|
|
// Hash the data.
|
|
scrambledToken := lhash.Digest(sh.opts.Algorithm, token.Data).Bytes()
|
|
|
|
sh.verifiersLock.RLock()
|
|
defer sh.verifiersLock.RUnlock()
|
|
|
|
// Check if token is valid.
|
|
_, ok := sh.verifiers[string(scrambledToken)]
|
|
if !ok {
|
|
return ErrTokenInvalid
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetToken returns a token.
|
|
func (sh *ScrambleHandler) GetToken() (*Token, error) {
|
|
sh.storageLock.Lock()
|
|
defer sh.storageLock.Unlock()
|
|
|
|
if len(sh.Storage) == 0 {
|
|
return nil, ErrEmpty
|
|
}
|
|
|
|
return &Token{
|
|
Zone: sh.opts.Zone,
|
|
Data: sh.Storage[0].Token,
|
|
}, nil
|
|
}
|
|
|
|
// ScrambleStorage is a storage for scramble tokens.
|
|
type ScrambleStorage struct {
|
|
Storage []*ScrambleToken
|
|
}
|
|
|
|
// Save serializes and returns the current tokens.
|
|
func (sh *ScrambleHandler) Save() ([]byte, error) {
|
|
sh.storageLock.Lock()
|
|
defer sh.storageLock.Unlock()
|
|
|
|
if len(sh.Storage) == 0 {
|
|
return nil, ErrEmpty
|
|
}
|
|
|
|
s := &ScrambleStorage{
|
|
Storage: sh.Storage,
|
|
}
|
|
|
|
return dsd.Dump(s, dsd.CBOR)
|
|
}
|
|
|
|
// Load loads the given tokens into the handler.
|
|
func (sh *ScrambleHandler) Load(data []byte) error {
|
|
sh.storageLock.Lock()
|
|
defer sh.storageLock.Unlock()
|
|
|
|
s := &ScrambleStorage{}
|
|
_, err := dsd.Load(data, s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sh.Storage = s.Storage
|
|
return nil
|
|
}
|
|
|
|
// Clear clears all the tokens in the handler.
|
|
func (sh *ScrambleHandler) Clear() {
|
|
sh.storageLock.Lock()
|
|
defer sh.storageLock.Unlock()
|
|
|
|
sh.Storage = nil
|
|
}
|