authtest

package
v0.8.2 Latest Latest
Warning

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

Go to latest
Published: Oct 14, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package authtest provides an in-memory auth.Store for tests.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type MemStore

type MemStore struct {
	// MemStore keeps the app configuration state and history.
	appconfig.MemStore

	// FailPutIdentity, when set, is returned by PutIdentity.
	FailPutIdentity error
	// contains filtered or unexported fields
}

MemStore is an in-memory auth.Store. The zero value is not usable; use NewMemStore.

func NewMemStore

func NewMemStore() *MemStore

NewMemStore returns an empty store.

func (*MemStore) APIKeyByHash

func (m *MemStore) APIKeyByHash(_ context.Context, hash string) (auth.APIKey, error)

func (*MemStore) AcquireLoginLock added in v0.5.0

func (m *MemStore) AcquireLoginLock(_ context.Context, key, owner string, now, until time.Time) (bool, error)

AcquireLoginLock and ReleaseLoginLock keep the locks apart from the counters.

func (*MemStore) AddEraseCount added in v0.4.0

func (m *MemStore) AddEraseCount(_ context.Context, jobID, key string, n int64) error

func (*MemStore) AddPushSend added in v0.8.2

func (m *MemStore) AddPushSend(_ context.Context, id string, d auth.PushDelta, now time.Time) (auth.PushSend, error)

func (*MemStore) AddRoles

func (m *MemStore) AddRoles(_ context.Context, userID string, roles []string, now time.Time) error

func (*MemStore) AddStorageUsage added in v0.8.0

func (m *MemStore) AddStorageUsage(_ context.Context, owner string, bytes, files int64) error

func (*MemStore) AdvanceMFAStep added in v0.8.2

func (m *MemStore) AdvanceMFAStep(_ context.Context, userID string, step int64) (bool, error)

func (*MemStore) AppendAudit

func (m *MemStore) AppendAudit(_ context.Context, rec auth.AuditRecord) error

func (*MemStore) AppendConsentRecord added in v0.8.2

func (m *MemStore) AppendConsentRecord(_ context.Context, r auth.ConsentRecord) error

func (*MemStore) AudienceUserIDs added in v0.8.2

func (m *MemStore) AudienceUserIDs(_ context.Context, a auth.PushAudience, after string, limit int) ([]string, error)

func (*MemStore) AuditRecords

func (m *MemStore) AuditRecords() []auth.AuditRecord

AuditRecords returns every stored audit record, oldest first.

func (*MemStore) CancelJob added in v0.8.0

func (m *MemStore) CancelJob(_ context.Context, id string, result auth.JobResult, steps []auth.Step, completedAt, expiresAt time.Time) (bool, error)

func (*MemStore) ChallengeByToken added in v0.8.2

func (m *MemStore) ChallengeByToken(_ context.Context, tokenHash, kind string, now time.Time) (auth.AuthChallenge, error)

func (*MemStore) ChallengeOfUser added in v0.8.2

func (m *MemStore) ChallengeOfUser(_ context.Context, userID, kind string, now time.Time) (auth.AuthChallenge, error)

func (*MemStore) ClaimChallenge added in v0.8.2

func (m *MemStore) ClaimChallenge(_ context.Context, id string, now time.Time) (auth.AuthChallenge, error)

func (*MemStore) ClaimDirectUpload added in v0.8.0

func (m *MemStore) ClaimDirectUpload(_ context.Context, id, tokenHash string, now time.Time) (auth.FileJournalEntry, error)

func (*MemStore) ClaimFileDeletions added in v0.8.0

func (m *MemStore) ClaimFileDeletions(_ context.Context, now, lease time.Time, limit int) ([]auth.FileDeletion, error)

func (*MemStore) ClaimIdempotency

func (m *MemStore) ClaimIdempotency(_ context.Context, rec auth.IdempotencyRecord) (auth.IdempotencyRecord, bool, error)

ClaimIdempotency inserts rec if its id isn't already used, mirroring the MongoDB store's insert-or-fetch-existing atomicity (a single mutex makes this trivially atomic here).

func (*MemStore) ClaimInvitation

func (m *MemStore) ClaimInvitation(_ context.Context, hash string, now time.Time) (auth.Invitation, error)

func (*MemStore) ClaimInvitationByID added in v0.4.0

func (m *MemStore) ClaimInvitationByID(_ context.Context, id string, now time.Time) (auth.Invitation, error)

func (*MemStore) ClaimJob

func (m *MemStore) ClaimJob(_ context.Context, workerID string, at time.Time, margin time.Duration) (auth.Job, bool, error)

ClaimJob picks the oldest job that's never been claimed, or whose lease has expired, the same rule the MongoDB store's query applies.

func (*MemStore) ClaimLoginCode added in v0.8.2

func (m *MemStore) ClaimLoginCode(_ context.Context, id string, now time.Time) (auth.LoginCode, error)

func (*MemStore) ClaimOAuthState added in v0.8.2

func (m *MemStore) ClaimOAuthState(_ context.Context, id string, now time.Time) (auth.OAuthState, error)

func (*MemStore) ClaimPendingUpload added in v0.8.0

func (m *MemStore) ClaimPendingUpload(_ context.Context, id, tokenHash, documentID string, now time.Time) (auth.FileJournalEntry, error)

func (*MemStore) ClearEraseEmail added in v0.4.0

func (m *MemStore) ClearEraseEmail(_ context.Context, jobID string) error

func (*MemStore) ClearJobInput added in v0.8.2

func (m *MemStore) ClearJobInput(_ context.Context, jobID string) error

func (*MemStore) ClearLoginAttempts

func (m *MemStore) ClearLoginAttempts(_ context.Context, key string) error

func (*MemStore) ClearRevokeToken added in v0.8.2

func (m *MemStore) ClearRevokeToken(_ context.Context, jobID string) error

func (*MemStore) CompleteFileDeletion added in v0.8.0

func (m *MemStore) CompleteFileDeletion(_ context.Context, key string) error

func (*MemStore) CompleteIdempotency

func (m *MemStore) CompleteIdempotency(_ context.Context, id string, result *auth.JobResult, jobID string, completedAt, expiresAt time.Time) error

func (*MemStore) CompleteJob

func (m *MemStore) CompleteJob(_ context.Context, id string, result auth.JobResult, completedAt, expiresAt time.Time) error

func (*MemStore) CompletePendingUpload added in v0.8.0

func (m *MemStore) CompletePendingUpload(_ context.Context, id, name, contentType, sha256sum string, size int64, uploadedAt time.Time, image string, at time.Time) error

func (*MemStore) ConsentVersionsInUse added in v0.8.2

func (m *MemStore) ConsentVersionsInUse(_ context.Context) ([]auth.ConsentRef, error)

func (*MemStore) CountChallengeAttempt added in v0.8.2

func (m *MemStore) CountChallengeAttempt(_ context.Context, id string, now time.Time) (auth.AuthChallenge, error)

func (*MemStore) CountOpenPendingUploads added in v0.8.0

func (m *MemStore) CountOpenPendingUploads(_ context.Context, callerKey string, now time.Time) (int, error)

func (*MemStore) CounterKeys added in v0.4.0

func (m *MemStore) CounterKeys() []string

CounterKeys returns the keys of every counter, for tests.

func (*MemStore) CreateAPIKey

func (m *MemStore) CreateAPIKey(_ context.Context, k auth.APIKey) error

func (*MemStore) CreateEmailToken added in v0.4.0

func (m *MemStore) CreateEmailToken(_ context.Context, t auth.EmailToken) error

func (*MemStore) CreateInvitation

func (m *MemStore) CreateInvitation(_ context.Context, inv auth.Invitation) error

func (*MemStore) CreatePushSend added in v0.8.2

func (m *MemStore) CreatePushSend(_ context.Context, p auth.PushSend) error

func (*MemStore) CreateSession

func (m *MemStore) CreateSession(_ context.Context, s auth.Session) error

func (*MemStore) CreateUser

func (m *MemStore) CreateUser(_ context.Context, u auth.User) error

func (*MemStore) DeleteAPIKey

func (m *MemStore) DeleteAPIKey(_ context.Context, name string) error

func (*MemStore) DeleteChallenge added in v0.8.2

func (m *MemStore) DeleteChallenge(_ context.Context, id string) error

func (*MemStore) DeleteChallengesOfUser added in v0.8.2

func (m *MemStore) DeleteChallengesOfUser(_ context.Context, userID string, kinds ...string) error

func (*MemStore) DeleteConsentRecordsOf added in v0.8.2

func (m *MemStore) DeleteConsentRecordsOf(_ context.Context, userID string) (int64, error)

func (*MemStore) DeleteDevice added in v0.8.2

func (m *MemStore) DeleteDevice(_ context.Context, userID, id string) error

func (*MemStore) DeleteDeviceByID added in v0.8.2

func (m *MemStore) DeleteDeviceByID(_ context.Context, id string) error

func (*MemStore) DeleteDevicesOfPlatform added in v0.8.2

func (m *MemStore) DeleteDevicesOfPlatform(_ context.Context, platform string) (int64, error)

func (*MemStore) DeleteEmailJobsOfUser added in v0.4.0

func (m *MemStore) DeleteEmailJobsOfUser(_ context.Context, userID string) error

func (*MemStore) DeleteEmailTokensOfUser added in v0.4.0

func (m *MemStore) DeleteEmailTokensOfUser(_ context.Context, userID string) error

func (*MemStore) DeleteIdentity added in v0.8.2

func (m *MemStore) DeleteIdentity(_ context.Context, userID, provider string) error

func (*MemStore) DeleteInvitation

func (m *MemStore) DeleteInvitation(_ context.Context, id string) error

func (*MemStore) DeleteMFA added in v0.8.2

func (m *MemStore) DeleteMFA(_ context.Context, userID string) error

func (*MemStore) DeleteOldestDevices added in v0.8.2

func (m *MemStore) DeleteOldestDevices(_ context.Context, userID string, keep int, keepID string) (int64, error)

func (*MemStore) DeleteOrphanedDevices added in v0.8.2

func (m *MemStore) DeleteOrphanedDevices(_ context.Context, now time.Time) (int64, error)

func (*MemStore) DeleteOtherSessions

func (m *MemStore) DeleteOtherSessions(_ context.Context, userID, keepID string) (int64, error)

func (*MemStore) DeleteSecret

func (m *MemStore) DeleteSecret(_ context.Context, database, name string) error

func (*MemStore) DeleteSession

func (m *MemStore) DeleteSession(_ context.Context, userID, id string) error

func (*MemStore) DeleteSessions

func (m *MemStore) DeleteSessions(_ context.Context, userID string) (int64, error)

func (*MemStore) DeleteStaleDevices added in v0.8.2

func (m *MemStore) DeleteStaleDevices(_ context.Context, before time.Time) (int64, error)

func (*MemStore) DeleteUser

func (m *MemStore) DeleteUser(_ context.Context, id string) error

func (*MemStore) Deletions added in v0.8.0

func (m *MemStore) Deletions() []auth.FileDeletion

Deletions returns the queued deletions, for tests.

func (*MemStore) DevicesByIDs added in v0.8.2

func (m *MemStore) DevicesByIDs(_ context.Context, ids []string) ([]auth.Device, error)

func (*MemStore) EmailTokens added in v0.4.0

func (m *MemStore) EmailTokens() []auth.EmailToken

EmailTokens returns every stored token record, for tests.

func (*MemStore) EnqueueJob

func (m *MemStore) EnqueueJob(_ context.Context, j auth.Job) error

func (*MemStore) EraseUser added in v0.4.0

func (m *MemStore) EraseUser(_ context.Context, id, placeholderEmail string, now time.Time) error

func (*MemStore) FileDeletionStats added in v0.8.0

func (m *MemStore) FileDeletionStats(_ context.Context) (auth.FileDeletionStats, error)

func (*MemStore) FileJournalEntry added in v0.8.0

func (m *MemStore) FileJournalEntry(_ context.Context, id string) (auth.FileJournalEntry, error)

func (*MemStore) GetChallenge added in v0.8.2

func (m *MemStore) GetChallenge(_ context.Context, id string, now time.Time) (auth.AuthChallenge, error)

func (*MemStore) GetCheckReport added in v0.8.0

func (m *MemStore) GetCheckReport(_ context.Context, database, collection string) (auth.CheckReport, bool, error)

func (*MemStore) GetEmailToken added in v0.4.0

func (m *MemStore) GetEmailToken(_ context.Context, hash string) (auth.EmailToken, error)

func (*MemStore) GetJob

func (m *MemStore) GetJob(_ context.Context, id string) (auth.Job, bool, error)

func (*MemStore) Identity

func (m *MemStore) Identity(_ context.Context, provider, subject string) (auth.Identity, error)

func (*MemStore) IdentityOf added in v0.8.2

func (m *MemStore) IdentityOf(_ context.Context, userID, provider string) (auth.Identity, error)

func (*MemStore) ImageDeclarations added in v0.8.1

func (m *MemStore) ImageDeclarations(_ context.Context) (map[string]string, error)

func (*MemStore) IncrementCounter

func (m *MemStore) IncrementCounter(_ context.Context, key string, at, expires time.Time) (int, time.Time, error)

IncrementCounter is a fixed window, unlike RecordLoginFailure's sliding cleanup deadline: expires (and so the reset) only moves once the current window has actually ended, or a steady stream of calls would push the deadline forward forever and never reset the count.

func (*MemStore) InvalidateEmailTokens added in v0.4.0

func (m *MemStore) InvalidateEmailTokens(_ context.Context, userID, purpose string, now time.Time) error

func (*MemStore) JournalEntry added in v0.8.0

func (m *MemStore) JournalEntry(id string) (auth.FileJournalEntry, bool)

JournalEntry returns an upload's record, for tests.

func (*MemStore) JournalFile added in v0.8.0

func (m *MemStore) JournalFile(_ context.Context, e auth.FileJournalEntry) error

func (*MemStore) ListAPIKeys

func (m *MemStore) ListAPIKeys(context.Context) ([]auth.APIKey, error)

func (*MemStore) ListAudit

func (m *MemStore) ListAudit(_ context.Context, f auth.AuditFilter) ([]auth.AuditRecord, bool, error)

ListAudit filters like the MongoDB store, newest first. Expired records are kept, as before MongoDB's TTL monitor removes them.

func (*MemStore) ListCheckReports added in v0.8.0

func (m *MemStore) ListCheckReports(_ context.Context, documents bool) ([]auth.CheckReport, error)

func (*MemStore) ListConsentRecords added in v0.8.2

func (m *MemStore) ListConsentRecords(_ context.Context, userID string) ([]auth.ConsentRecord, error)

func (*MemStore) ListDevices added in v0.8.2

func (m *MemStore) ListDevices(_ context.Context, userID string) ([]auth.Device, error)

func (*MemStore) ListIdentities added in v0.8.2

func (m *MemStore) ListIdentities(_ context.Context, userID string) ([]auth.Identity, error)

func (*MemStore) ListInvitations

func (m *MemStore) ListInvitations(context.Context) ([]auth.Invitation, error)

func (*MemStore) ListInvocations

func (m *MemStore) ListInvocations(_ context.Context, f auth.InvocationFilter) ([]auth.InvocationRecord, bool, error)

ListInvocations filters like the MongoDB store, newest first. Expired records are kept, as before MongoDB's TTL monitor removes them.

func (*MemStore) ListJobs

func (m *MemStore) ListJobs(_ context.Context, f auth.JobFilter) ([]auth.Job, bool, error)

ListJobs filters like the MongoDB store, newest first.

func (*MemStore) ListPushOutbox added in v0.8.2

func (m *MemStore) ListPushOutbox(_ context.Context, limit int) ([]auth.PushOutboxEntry, error)

func (*MemStore) ListPushSends added in v0.8.2

func (m *MemStore) ListPushSends(_ context.Context, f auth.PushSendFilter) ([]auth.PushSend, bool, error)

func (*MemStore) ListScheduleStates added in v0.8.0

func (m *MemStore) ListScheduleStates(context.Context) ([]auth.ScheduleState, error)

func (*MemStore) ListSecrets

func (m *MemStore) ListSecrets(context.Context) ([]auth.Secret, error)

func (*MemStore) ListSessions

func (m *MemStore) ListSessions(_ context.Context, userID string) ([]auth.Session, error)

func (*MemStore) ListUnverifiedUsers added in v0.4.0

func (m *MemStore) ListUnverifiedUsers(_ context.Context, before time.Time, limit int) ([]auth.User, error)

func (*MemStore) ListUsers

func (m *MemStore) ListUsers(context.Context) ([]auth.User, error)

func (*MemStore) ListUsersPage added in v0.5.0

func (m *MemStore) ListUsersPage(ctx context.Context, contains, after string, skip, limit int) ([]auth.User, bool, error)

func (*MemStore) LiveDevicesOf added in v0.8.2

func (m *MemStore) LiveDevicesOf(_ context.Context, userIDs []string, now time.Time) (map[string][]auth.Device, error)

func (*MemStore) LoginAttempts

func (m *MemStore) LoginAttempts(_ context.Context, key string) (auth.Attempts, error)

LoginAttempts returns the counter even past its expiry, like MongoDB before its TTL monitor deletes it; a failure after expiry restarts it.

func (*MemStore) MFAOf added in v0.8.2

func (m *MemStore) MFAOf(_ context.Context, userID string) (auth.MFARecord, error)

func (*MemStore) MFAUserIDs added in v0.8.2

func (m *MemStore) MFAUserIDs(_ context.Context) ([]string, error)

func (*MemStore) PurgeConsentRecords added in v0.8.2

func (m *MemStore) PurgeConsentRecords(now time.Time) int

PurgeConsentRecords removes the records whose retention ended, as the database's TTL does.

func (*MemStore) PushSendByID added in v0.8.2

func (m *MemStore) PushSendByID(_ context.Context, id string) (auth.PushSend, error)

func (*MemStore) PutChallenge added in v0.8.2

func (m *MemStore) PutChallenge(_ context.Context, c auth.AuthChallenge) error

func (*MemStore) PutDevice added in v0.8.2

func (m *MemStore) PutDevice(_ context.Context, d auth.Device) (auth.Device, bool, error)

func (*MemStore) PutIdentity

func (m *MemStore) PutIdentity(_ context.Context, id auth.Identity) error

func (*MemStore) PutLoginCode added in v0.8.2

func (m *MemStore) PutLoginCode(_ context.Context, lc auth.LoginCode) error

func (*MemStore) PutMFA added in v0.8.2

func (m *MemStore) PutMFA(_ context.Context, rec auth.MFARecord) error

func (*MemStore) PutOAuthState added in v0.8.2

func (m *MemStore) PutOAuthState(_ context.Context, st auth.OAuthState) error

func (*MemStore) PutPushOutbox added in v0.8.2

func (m *MemStore) PutPushOutbox(_ context.Context, e auth.PushOutboxEntry) error

func (*MemStore) QueueFileDeletion added in v0.8.0

func (m *MemStore) QueueFileDeletion(_ context.Context, d auth.FileDeletion) error

func (*MemStore) RecordInvocation

func (m *MemStore) RecordInvocation(_ context.Context, r auth.InvocationRecord) error

func (*MemStore) RecordLoginFailure

func (m *MemStore) RecordLoginFailure(_ context.Context, key string, at, expires time.Time) error

func (*MemStore) RedeemEmailToken added in v0.4.0

func (m *MemStore) RedeemEmailToken(_ context.Context, hash, purpose string, now time.Time) (auth.EmailToken, error)

func (*MemStore) ReduceConsentRecords added in v0.8.2

func (m *MemStore) ReduceConsentRecords(_ context.Context, userID, pseudonym string, deleteAt time.Time) (int64, error)

func (*MemStore) ReleaseIdempotency

func (m *MemStore) ReleaseIdempotency(_ context.Context, id string) error

func (*MemStore) ReleaseLoginLock added in v0.5.0

func (m *MemStore) ReleaseLoginLock(_ context.Context, key, owner string) error

func (*MemStore) ReleaseUpload added in v0.8.0

func (m *MemStore) ReleaseUpload(_ context.Context, id, status string, at time.Time) error

func (*MemStore) RemoveRole

func (m *MemStore) RemoveRole(_ context.Context, userID, role string, now time.Time) error

func (*MemStore) RenewJobLease added in v0.8.0

func (m *MemStore) RenewJobLease(_ context.Context, id string, attempt int, until time.Time) (bool, error)

func (*MemStore) ReopenJob added in v0.4.0

func (m *MemStore) ReopenJob(_ context.Context, id string, expiresAt time.Time) (bool, error)

func (*MemStore) RetryFileDeletion added in v0.8.0

func (m *MemStore) RetryFileDeletion(_ context.Context, key string, notBefore time.Time) error

func (*MemStore) RetryJob added in v0.4.0

func (m *MemStore) RetryJob(_ context.Context, id string, notBefore time.Time) error

func (*MemStore) SecretByScope

func (m *MemStore) SecretByScope(_ context.Context, database, name string) (auth.Secret, error)

func (*MemStore) Session

func (m *MemStore) Session(id string) (auth.Session, bool)

Session returns a stored session by id.

func (*MemStore) SessionByTokenHash

func (m *MemStore) SessionByTokenHash(_ context.Context, hash string) (auth.Session, auth.User, error)

func (*MemStore) SessionCount

func (m *MemStore) SessionCount(userID string) int

SessionCount returns how many sessions the user has, expired or not.

func (*MemStore) SetChallengeSecrets added in v0.8.2

func (m *MemStore) SetChallengeSecrets(_ context.Context, id, tokenHash, codeHash string, now time.Time) (auth.AuthChallenge, error)

func (*MemStore) SetCheckReport added in v0.8.0

func (m *MemStore) SetCheckReport(_ context.Context, r auth.CheckReport) error

func (*MemStore) SetFileJournalStatus added in v0.8.0

func (m *MemStore) SetFileJournalStatus(_ context.Context, id, status, documentID string, at, expiresAt time.Time) error

func (*MemStore) SetImageDeclaration added in v0.8.1

func (m *MemStore) SetImageDeclaration(_ context.Context, key, fingerprint string) error

func (*MemStore) SetJobSteps added in v0.8.0

func (m *MemStore) SetJobSteps(_ context.Context, id string, attempt int, steps []auth.Step, omitted int) (bool, error)

func (*MemStore) SetPushPlanPosition added in v0.8.2

func (m *MemStore) SetPushPlanPosition(_ context.Context, jobID, after string, nextBatch int) error

func (*MemStore) SetPushPlanned added in v0.8.2

func (m *MemStore) SetPushPlanned(_ context.Context, id string, batches int, now time.Time) error

func (*MemStore) SetScheduleState added in v0.8.0

func (m *MemStore) SetScheduleState(_ context.Context, st auth.ScheduleState) error

func (*MemStore) SetUserConsent added in v0.8.2

func (m *MemStore) SetUserConsent(_ context.Context, userID, consent, version string) error

func (*MemStore) StaleFileJournal added in v0.8.0

func (m *MemStore) StaleFileJournal(_ context.Context, before, now time.Time, limit int) ([]auth.FileJournalEntry, error)

func (*MemStore) StorageUsage added in v0.8.0

func (m *MemStore) StorageUsage(_ context.Context, limit int) (auth.StorageUsage, error)

func (*MemStore) StorageUsageOf added in v0.8.1

func (*MemStore) TouchAPIKey

func (m *MemStore) TouchAPIKey(_ context.Context, hash string, at time.Time) error

func (*MemStore) TouchSession

func (m *MemStore) TouchSession(_ context.Context, id string, lastUsed, expires time.Time) error

func (*MemStore) UpdateIdentity added in v0.8.2

func (m *MemStore) UpdateIdentity(_ context.Context, id string, upd auth.IdentityUpdate, now time.Time) error

func (*MemStore) UpdatePushRecipients added in v0.8.2

func (m *MemStore) UpdatePushRecipients(_ context.Context, jobID string, recipients []auth.PushRecipient) error

func (*MemStore) UpdateUser

func (m *MemStore) UpdateUser(_ context.Context, id string, upd auth.UserUpdate, now time.Time) error

func (*MemStore) UpsertSecret

func (m *MemStore) UpsertSecret(_ context.Context, s auth.Secret) error

func (*MemStore) UseRecoveryCode added in v0.8.2

func (m *MemStore) UseRecoveryCode(_ context.Context, userID, hash string) (int, bool, error)

func (*MemStore) UserByEmail

func (m *MemStore) UserByEmail(_ context.Context, email string) (auth.User, error)

func (*MemStore) UserByID

func (m *MemStore) UserByID(_ context.Context, id string) (auth.User, error)

func (*MemStore) UsersByIDs added in v0.8.2

func (m *MemStore) UsersByIDs(_ context.Context, ids []string) ([]auth.User, error)

Jump to

Keyboard shortcuts

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