instance

package
v0.0.0-...-820a931 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 23, 2024 License: AGPL-3.0 Imports: 42 Imported by: 41

Documentation

Overview

Package instance is for the instance model, with domain, locale, settings, etc.

Index

Constants

View Source
const (
	RegisterTokenLen      = 16
	PasswordResetTokenLen = 16
	SessionCodeLen        = 32
	EmailVerifiedCodeLen  = 32
	SessionSecretLen      = 64
	MagicLinkCodeLen      = 32
	OauthSecretLen        = 128
)

This is the lengths of our tokens (in bytes).

View Source
const DefaultTemplateTitle = "Cozy"

DefaultTemplateTitle represents the default template title. It could be overrided by configuring it in the instance context parameters

View Source
const PBKDF2_SHA256 = 0

PBKDF2_SHA256 is the value of kdf for using PBKDF2 with SHA256 to hash the password on client side.

Variables

View Source
var (
	// ErrNotFound is used when the seeked instance was not found
	ErrNotFound = errors.New("Instance not found")
	// ErrExists is used the instance already exists
	ErrExists = errors.New("Instance already exists")
	// ErrIllegalDomain is used when the domain named contains illegal characters
	ErrIllegalDomain = errors.New("Domain name contains illegal characters")
	// ErrMissingToken is returned by RegisterPassphrase if token is empty
	ErrMissingToken = errors.New("Empty register token")
	// ErrInvalidToken is returned by RegisterPassphrase if token is invalid
	ErrInvalidToken = errors.New("Invalid register token")
	// ErrMissingPassphrase is returned when the new passphrase is missing
	ErrMissingPassphrase = errors.New("Missing new passphrase")
	// ErrInvalidPassphrase is returned when the passphrase is invalid
	ErrInvalidPassphrase = errors.New("Invalid passphrase")
	// ErrInvalidTwoFactor is returned when the two-factor authentication
	// verification is invalid.
	ErrInvalidTwoFactor = errors.New("Invalid two-factor parameters")
	// ErrResetAlreadyRequested is returned when a passphrase reset token is already set and valid
	ErrResetAlreadyRequested = errors.New("The passphrase reset has already been requested")
	// ErrUnknownAuthMode is returned when an unknown authentication mode is
	// used.
	ErrUnknownAuthMode = errors.New("Unknown authentication mode")
	// ErrBadTOSVersion is returned when a malformed TOS version is provided.
	ErrBadTOSVersion = errors.New("Bad format for TOS version")
	// ErrInvalidSwiftLayout is returned when the Swift layout is unknown.
	ErrInvalidSwiftLayout = errors.New("Invalid Swift layout")
	// ErrDeletionAlreadyRequested is returned when a deletion has already been requested.
	ErrDeletionAlreadyRequested = errors.New("The deletion has already been requested")
)
View Source
var (
	// BlockedLoginFailed is used when a security issue has been detected on the instance
	BlockedLoginFailed = BlockingReason{Code: "LOGIN_FAILED", Message: "Instance Blocked Login"}
	// BlockedPaymentFailed is used when a payment is missing for the instance
	BlockedPaymentFailed = BlockingReason{Code: "PAYMENT_FAILED", Message: "Instance Blocked Payment"}
	// BlockedImporting is used when importing the data from another instance
	BlockedImporting = BlockingReason{Code: "IMPORTING", Message: "Instance Blocked Importing"}
	// BlockedMoving is used when moving data from another instance
	BlockedMoving = BlockingReason{Code: "MOVING", Message: "Instance Blocked Moving"}
	// BlockedUnknown is used when an instance is blocked but the reason is unknown
	BlockedUnknown = BlockingReason{Code: "UNKNOWN", Message: "Instance Blocked Unknown"}
)

Functions

func APIManagerClient

func APIManagerClient(inst *Instance) *manager.APIClient

APIManagerClient returns a client to talk to the manager via its API.

func AuthModeToString

func AuthModeToString(authMode AuthMode) string

AuthModeToString encode authentication mode in a string

func CheckPassphrase deprecated

func CheckPassphrase(inst *Instance, pass []byte) error

CheckPassphrase confirm an instance password

Deprecated: Use InstanceService.CheckPassphrase instead.

func Delete deprecated

func Delete(inst *Instance) error

Delete removes the instance document in CouchDB.

Deprecated: Use InstanceService.Delete instead.

func ForeachInstances

func ForeachInstances(fn func(*Instance) error) error

ForeachInstances execute the given callback for each instances.

func ParseTOSVersion

func ParseTOSVersion(v string) (major int, date time.Time, ok bool)

ParseTOSVersion returns the "major" and the date encoded in a version string with the following format:

parseTOSVersion(A.B.C-YYYYMMDD) -> (A, YYYY, true)

func Update deprecated

func Update(inst *Instance) error

Update saves the changes in CouchDB.

Deprecated: Use InstanceService.Update instead.

Types

type AppLogos

type AppLogos struct {
	Light []LogoItem `json:"light,omitempty"`
	Dark  []LogoItem `json:"dark,omitempty"`
}

type AuthMode

type AuthMode int

AuthMode defines the authentication mode chosen for the connection to this instance.

const (
	// Basic authentication mode, only passphrase
	Basic AuthMode = iota
	// TwoFactorMail authentication mode, with passcode sent via email
	TwoFactorMail
)

func StringToAuthMode

func StringToAuthMode(authMode string) (AuthMode, error)

StringToAuthMode converts a string encoded authentication mode into a AuthMode int.

type BlockingReason

type BlockingReason struct {
	Code    string
	Message string
}

BlockingReason structs holds a reason why an instance had been blocked

type Instance

type Instance struct {
	DocID           string   `json:"_id,omitempty"`  // couchdb _id
	DocRev          string   `json:"_rev,omitempty"` // couchdb _rev
	Domain          string   `json:"domain"`         // The main DNS domain, like example.cozycloud.cc
	DomainAliases   []string `json:"domain_aliases,omitempty"`
	Prefix          string   `json:"prefix,omitempty"`           // Possible database prefix
	Locale          string   `json:"locale"`                     // The locale used on the server
	UUID            string   `json:"uuid,omitempty"`             // UUID associated with the instance
	OIDCID          string   `json:"oidc_id,omitempty"`          // An identifier to check authentication from OIDC
	FranceConnectID string   `json:"franceconnect_id,omitempty"` // An identifier to check authentication from FranceConnect
	ContextName     string   `json:"context,omitempty"`          // The context attached to the instance
	Sponsorships    []string `json:"sponsorships,omitempty"`     // The list of sponsorships for the instance
	TOSSigned       string   `json:"tos,omitempty"`              // Terms of Service signed version
	TOSLatest       string   `json:"tos_latest,omitempty"`       // Terms of Service latest version
	AuthMode        AuthMode `json:"auth_mode,omitempty"`        // 2 factor authentication
	MagicLink       bool     `json:"magic_link,omitempty"`       // Authentication via a link sent by email
	Deleting        bool     `json:"deleting,omitempty"`
	Moved           bool     `json:"moved,omitempty"`           // If the instance has been moved to a new place
	Blocked         bool     `json:"blocked,omitempty"`         // Whether or not the instance is blocked
	BlockingReason  string   `json:"blocking_reason,omitempty"` // Why the instance is blocked
	NoAutoUpdate    bool     `json:"no_auto_update,omitempty"`  // Whether or not the instance has auto updates for its applications

	OnboardingFinished bool  `json:"onboarding_finished,omitempty"` // Whether or not the onboarding is complete.
	PasswordDefined    *bool `json:"password_defined"`              // 3 possibles states: true, false, and unknown (for legacy reasons)

	BytesDiskQuota    int64 `json:"disk_quota,string,omitempty"` // The total size in bytes allowed to the user
	IndexViewsVersion int   `json:"indexes_version,omitempty"`

	// Swift layout number:
	// - 0 for layout v1
	// - 1 for layout v2
	// - 2 for layout v3
	// It is called swift_cluster in CouchDB and indexed from 0 for legacy reasons.
	// See model/vfs/vfsswift for more details.
	SwiftLayout int `json:"swift_cluster,omitempty"`

	CouchCluster int `json:"couch_cluster,omitempty"`

	// PassphraseHash is a hash of a hash of the user's passphrase: the
	// passphrase is first hashed in client-side to avoid sending it to the
	// server as it also used for encryption on client-side, and after that,
	// hashed on the server to ensure robustness. For more informations on the
	// server-side hashing, see crypto.GenerateFromPassphrase.
	PassphraseHash       []byte     `json:"passphrase_hash,omitempty"`
	PassphraseResetToken []byte     `json:"passphrase_reset_token,omitempty"`
	PassphraseResetTime  *time.Time `json:"passphrase_reset_time,omitempty"`

	// Register token is used on registration to prevent from stealing instances
	// waiting for registration. The registerToken secret is only shared (in
	// clear) with the instance's user.
	RegisterToken []byte `json:"register_token,omitempty"`
	// SessSecret is used to authenticate session cookies
	SessSecret []byte `json:"session_secret,omitempty"`
	// OAuthSecret is used to authenticate OAuth2 token
	OAuthSecret []byte `json:"oauth_secret,omitempty"`
	// CLISecret is used to authenticate request from the CLI
	CLISecret []byte `json:"cli_secret,omitempty"`

	// FeatureFlags is the feature flags that are specific to this instance
	FeatureFlags map[string]interface{} `json:"feature_flags,omitempty"`
	// FeatureSets is a list of feature sets from the manager
	FeatureSets []string `json:"feature_sets,omitempty"`

	// LastActivityFromDeletedOAuthClients is the date of the last activity for
	// OAuth clients that have been deleted
	LastActivityFromDeletedOAuthClients *time.Time `json:"last_activity_from_deleted_oauth_clients,omitempty"`
	// contains filtered or unexported fields
}

An Instance has the informations relatives to the logical cozy instance, like the domain, the locale or the access to the databases and files storage It is a couchdb.Doc to be persisted in couchdb.

func Get deprecated

func Get(domain string) (*Instance, error)

Get finds an instance from its domain by using CouchDB.

Deprecated: Use InstanceService.Get instead.

func List

func List() ([]*Instance, error)

List returns the list of declared instances.

func PaginatedList

func PaginatedList(limit int, startKey string, skip int) ([]*Instance, string, error)

PaginatedList can be used to list the instances, with pagination.

func (*Instance) BuildAppToken

func (i *Instance) BuildAppToken(slug, sessionID string) string

BuildAppToken is used to build a token to identify the app for requests made to the stack

func (*Instance) BuildKonnectorToken

func (i *Instance) BuildKonnectorToken(slug string) string

BuildKonnectorToken is used to build a token to identify the konnector for requests made to the stack

func (*Instance) ChangePasswordURL

func (i *Instance) ChangePasswordURL() string

ChangePasswordURL returns the URL of the settings page that can be used by the user to change their password.

func (*Instance) CheckAndClearSessionCode

func (i *Instance) CheckAndClearSessionCode(code string) bool

CheckAndClearSessionCode will return true if the session code is valid. The session code can only be used once, so it will be cleared after calling this function.

func (*Instance) CheckEmailVerifiedCode

func (i *Instance) CheckEmailVerifiedCode(code string) bool

CheckEmailVerifiedCode will return true if the email verified code is valid.

func (*Instance) CheckInstanceBlocked

func (i *Instance) CheckInstanceBlocked() bool

CheckInstanceBlocked returns whether or not the instance is currently in a blocked state: meaning it should be accessible.

func (*Instance) CheckTOSNotSigned

func (i *Instance) CheckTOSNotSigned(args ...string) (notSigned bool)

CheckTOSNotSigned checks whether or not the current Term of Services have been signed by the user.

func (*Instance) CheckTOSNotSignedAndDeadline

func (i *Instance) CheckTOSNotSignedAndDeadline(args ...string) (notSigned bool, deadline TOSDeadline)

CheckTOSNotSignedAndDeadline checks whether or not the current Term of Services have been signed by the user and returns the deadline state to perform this signature.

func (*Instance) Clone

func (i *Instance) Clone() couchdb.Doc

Clone implements couchdb.Doc

func (*Instance) ContextualDomain

func (i *Instance) ContextualDomain() string

ContextualDomain returns the domain with regard to the current domain request.

func (*Instance) CreateEmailVerifiedCode

func (i *Instance) CreateEmailVerifiedCode() (string, error)

CreateEmailVerifiedCode returns an email_verified_code that can be used to avoid the 2FA by email.

func (*Instance) CreateSessionCode

func (i *Instance) CreateSessionCode() (string, error)

CreateSessionCode returns a session_code that can be used to open a webview inside the flagship app and create the session.

func (*Instance) CreateShareCode

func (i *Instance) CreateShareCode(subject string) (string, error)

CreateShareCode returns a new sharecode to put the codes field of a permissions document

func (*Instance) DBCluster

func (i *Instance) DBCluster() int

DBCluster returns the index of the CouchDB cluster where the databases for this instance can be found.

func (*Instance) DBPrefix

func (i *Instance) DBPrefix() string

DBPrefix returns the prefix to use in database naming for the current instance

func (*Instance) DefaultAppAndPath

func (i *Instance) DefaultAppAndPath() string

DefaultAppAndPath returns the default_redirection from the context, in the slug+path format (or use the home as the default application).

func (*Instance) DefaultRedirection

func (i *Instance) DefaultRedirection() *url.URL

DefaultRedirection returns the URL where to redirect the user afer login (and in most other cases where we need a redirection URL)

func (*Instance) DefaultRedirectionFromContext

func (i *Instance) DefaultRedirectionFromContext() *url.URL

DefaultRedirectionFromContext returns the URL where to redirect the user after login from the context parameters. It can be overloaded by instance via the "default_redirection" setting.

func (*Instance) DirName

func (i *Instance) DirName() string

DirName returns the name of the subdirectory where instance data are stored. On Posix systems, it's the instance domain name.

func (*Instance) DiskQuota

func (i *Instance) DiskQuota() int64

DiskQuota returns the number of bytes allowed on the disk to the user.

func (*Instance) DocType

func (i *Instance) DocType() string

DocType implements couchdb.Doc

func (*Instance) DomainName

func (i *Instance) DomainName() string

DomainName returns the main domain name of the instance.

func (*Instance) EnsureSharedDrivesDir

func (i *Instance) EnsureSharedDrivesDir() (*vfs.DirDoc, error)

EnsureSharedDrivesDir returns the Shared Drives directory, and creates it if it doesn't exist

func (*Instance) FromURL

func (i *Instance) FromURL(u *url.URL) string

FromURL normalizes a given url with the scheme and domain of the instance.

func (*Instance) GenerateMailConfirmationCode

func (i *Instance) GenerateMailConfirmationCode() (string, error)

GenerateMailConfirmationCode generates a code for validating the user's email.

func (*Instance) GenerateTwoFactorSecrets

func (i *Instance) GenerateTwoFactorSecrets() (token []byte, passcode string, err error)

GenerateTwoFactorSecrets generates a (token, passcode) pair that can be used as a two factor authentication secret value. The token is used to allow the two-factor form — meaning the user has correctly entered its passphrase and successfully done the first part of the two factor authentication.

The passcode should be send to the user by another mean (mail, SMS, ...)

func (*Instance) GenerateTwoFactorTrustedDeviceSecret

func (i *Instance) GenerateTwoFactorTrustedDeviceSecret(req *http.Request) ([]byte, error)

GenerateTwoFactorTrustedDeviceSecret generates a token that can be kept by the user on-demand to avoid having two-factor authentication on a specific machine.

func (*Instance) GetContextName

func (i *Instance) GetContextName() string

GetContextName returns the name of the context.

func (*Instance) GetContextWithSponsorships

func (i *Instance) GetContextWithSponsorships() map[string]interface{}

func (*Instance) GetFromContexts

func (i *Instance) GetFromContexts(contexts map[string]interface{}) (interface{}, bool)

GetFromContexts returns the parameters specific to the instance context

func (*Instance) HasAuthMode

func (i *Instance) HasAuthMode(authMode AuthMode) bool

HasAuthMode returns whether or not the instance has the given authentication mode activated.

func (*Instance) HasDomain

func (i *Instance) HasDomain(domain string) bool

HasDomain returns whether or not the given domain name is owned by this instance, as part of its main domain name or its aliases.

func (*Instance) HasForcedOIDC

func (i *Instance) HasForcedOIDC() bool

HasForcedOIDC returns true only if the instance is in a context where the config says that the stack shouldn't allow to authenticate with the password.

func (*Instance) HasPremiumLinksEnabled

func (i *Instance) HasPremiumLinksEnabled() bool

func (*Instance) ID

func (i *Instance) ID() string

ID implements couchdb.Doc

func (*Instance) Logger

func (i *Instance) Logger() *logger.Entry

Logger returns the logger associated with the instance

func (*Instance) MakeJWT

func (i *Instance) MakeJWT(audience, subject, scope, sessionID string, issuedAt time.Time) (string, error)

MakeJWT is a shortcut to create a JWT

func (*Instance) MakeVFS

func (i *Instance) MakeVFS() error

MakeVFS is used to initialize the VFS linked to this instance

func (*Instance) ManagerURL

func (i *Instance) ManagerURL(k ManagerURLKind) (string, error)

ManagerURL returns an external string for the given ManagerURL kind. It is used for redirecting the user to a manager URL.

func (*Instance) MoveURL

func (i *Instance) MoveURL() string

MoveURL returns URL for move wizard.

func (*Instance) MovedError

func (i *Instance) MovedError() *jsonapi.Error

MovedError is used to return an error when the instance has been moved to a new domain/hoster.

func (*Instance) NotesLock

func (i *Instance) NotesLock() lock.ErrorRWLocker

NotesLock returns a mutex for the notes on this instance.

func (*Instance) OnboardedRedirection

func (i *Instance) OnboardedRedirection() *url.URL

OnboardedRedirection returns the URL where to redirect the user after onboarding

func (*Instance) PageURL

func (i *Instance) PageURL(path string, queries url.Values) string

PageURL returns the full URL for a path on the cozy stack

func (*Instance) PassphraseSalt

func (i *Instance) PassphraseSalt() []byte

PassphraseSalt computes the salt for the client-side hashing of the master password. The rule for computing the salt is to create a fake email address "me@<domain>".

func (*Instance) PickKey

func (i *Instance) PickKey(audience string) ([]byte, error)

PickKey choose which of the Instance keys to use depending on token audience

func (*Instance) Registries

func (i *Instance) Registries() []*url.URL

Registries returns the list of registries associated with the instance.

func (*Instance) Rev

func (i *Instance) Rev() string

Rev implements couchdb.Doc

func (*Instance) Scheme

func (i *Instance) Scheme() string

Scheme returns the scheme used for URLs. It is https by default and http for development instances.

func (*Instance) SessionSecret

func (i *Instance) SessionSecret() []byte

SessionSecret returns the session secret.

func (*Instance) SetID

func (i *Instance) SetID(v string)

SetID implements couchdb.Doc

func (*Instance) SetPasswordDefined

func (i *Instance) SetPasswordDefined(defined bool)

func (*Instance) SetRev

func (i *Instance) SetRev(v string)

SetRev implements couchdb.Doc

func (*Instance) SettingsContext

func (i *Instance) SettingsContext() (map[string]interface{}, bool)

SettingsContext returns the map from the config that matches the context of this instance

func (*Instance) SettingsDocument

func (i *Instance) SettingsDocument() (*couchdb.JSONDoc, error)

SettingsDocument returns the document with the settings of this instance

func (*Instance) SettingsEMail

func (i *Instance) SettingsEMail() (string, error)

SettingsEMail returns the email address defined in the settings of this instance.

func (*Instance) SettingsPublicName

func (i *Instance) SettingsPublicName() (string, error)

SettingsPublicName returns the public name defined in the settings of this instance.

func (*Instance) SlugAndDomain

func (i *Instance) SlugAndDomain() (string, string)

SlugAndDomain returns the splitted slug and domain of the instance Ex: foobar.mycozy.cloud => ["foobar", "mycozy.cloud"]

func (*Instance) SubDomain

func (i *Instance) SubDomain(s string) *url.URL

SubDomain returns the full url for a subdomain of this instance useful with apps slugs

func (*Instance) SupportEmailAddress

func (i *Instance) SupportEmailAddress() string

SupportEmailAddress returns the email address that can be used to contact the support.

func (*Instance) TemplateTitle

func (i *Instance) TemplateTitle() string

TemplateTitle returns the specific-context instance template title (if there is one). Otherwise, returns the default one

func (*Instance) ThumbsFS

func (i *Instance) ThumbsFS() vfs.Thumbser

ThumbsFS returns the hidden filesystem for storing the thumbnails of the photos/image

func (*Instance) Translate

func (i *Instance) Translate(key string, vars ...interface{}) string

Translate is used to translate a string to the locale used on this instance

func (*Instance) VFS

func (i *Instance) VFS() vfs.VFS

VFS returns the storage provider where the binaries for the current instance are persisted

func (*Instance) ValidateMailConfirmationCode

func (i *Instance) ValidateMailConfirmationCode(passcode string) bool

ValidateMailConfirmationCode returns true if the given passcode is valid.

func (*Instance) ValidateTwoFactorPasscode

func (i *Instance) ValidateTwoFactorPasscode(token []byte, passcode string) bool

ValidateTwoFactorPasscode validates the given (token, passcode) pair for two factor authentication.

func (*Instance) ValidateTwoFactorTrustedDeviceSecret

func (i *Instance) ValidateTwoFactorTrustedDeviceSecret(req *http.Request, token []byte) bool

ValidateTwoFactorTrustedDeviceSecret validates the given token used to check if the computer is trusted to avoid two-factor authorization.

func (*Instance) WithContextualDomain

func (i *Instance) WithContextualDomain(domain string) *Instance

WithContextualDomain the current instance context with the given hostname.

type InstanceService

type InstanceService struct {
	// contains filtered or unexported fields
}

func Init

func Init() *InstanceService

func NewService

func NewService(logger logger.Logger) *InstanceService

func (*InstanceService) CheckPassphrase

func (s *InstanceService) CheckPassphrase(inst *Instance, pass []byte) error

CheckPassphrase confirm an instance password

func (*InstanceService) Delete

func (s *InstanceService) Delete(inst *Instance) error

Delete removes the instance document in CouchDB.

func (*InstanceService) Get

func (s *InstanceService) Get(domain string) (*Instance, error)

Get finds an instance from its domain by using CouchDB.

func (*InstanceService) Update

func (s *InstanceService) Update(inst *Instance) error

Update saves the changes in CouchDB.

type LogoItem

type LogoItem struct {
	Src  string `json:"src"`
	Alt  string `json:"alt"`
	Type string `json:"type,omitempty"`
}

type ManagerURLKind

type ManagerURLKind int

ManagerURLKind is an enum type for the different kinds of manager URLs.

const (
	// ManagerTOSURL is the kind for changes of TOS URL.
	ManagerTOSURL ManagerURLKind = iota
	// ManagerPremiumURL is the kind for changing the account type of the
	// instance.
	ManagerPremiumURL
	// ManagerBlockedURL is the kind for a redirection of a blocked instance.
	ManagerBlockedURL
)

type Mock

type Mock struct {
	mock.Mock
}

Mock implementation of

func NewMock

func NewMock(t *testing.T) *Mock

NewMock instantiates a new Mock.

func (*Mock) CheckPassphrase

func (m *Mock) CheckPassphrase(inst *Instance, pass []byte) error

CheckPassphrase mock method.

func (*Mock) Delete

func (m *Mock) Delete(inst *Instance) error

Delete mock method.

func (*Mock) Get

func (m *Mock) Get(domain string) (*Instance, error)

Get mock method.

func (*Mock) Update

func (m *Mock) Update(inst *Instance) error

Update mock method.

type Service

type Service interface {
	Get(domain string) (*Instance, error)
	Update(inst *Instance) error
	Delete(inst *Instance) error
	CheckPassphrase(inst *Instance, pass []byte) error
}

Service handle all the interactions with the "instance" domain.

This interface has several implementations: - InstanceService with the business logic - Mock with a mock implementation

type Store

type Store interface {
	SaveSessionCode(db prefixer.Prefixer, code string) error
	SaveEmailVerfiedCode(db prefixer.Prefixer, code string) error
	CheckAndClearSessionCode(db prefixer.Prefixer, code string) bool
	CheckEmailVerifiedCode(db prefixer.Prefixer, code string) bool
}

Store is an object to store and retrieve session codes.

func GetStore

func GetStore() Store

GetStore returns the store for temporary move objects.

type TOSDeadline

type TOSDeadline int

TOSDeadline represent the state for reaching the TOS deadline.

const (
	// TOSNone when no deadline is reached.
	TOSNone TOSDeadline = iota
	// TOSWarning when the warning deadline is reached, 2 weeks before the actual
	// activation of the CGU.
	TOSWarning
	// TOSBlocked when the deadline is reached and the access should be blocked.
	TOSBlocked
)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL