snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
This commit is contained in:
19
text/context.go
Normal file
19
text/context.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func context(ctx map[string]any) []byte {
|
||||
if len(ctx) == 0 {
|
||||
panic("context must not be empty")
|
||||
}
|
||||
res, err := json.Marshal(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return res
|
||||
}
|
||||
233
text/id.go
Normal file
233
text/id.go
Normal file
@@ -0,0 +1,233 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
// This file MUST not have any imports to modules that are not in the standard library.
|
||||
// Otherwise, `make docs/cli` will fail.
|
||||
|
||||
type ID int
|
||||
|
||||
const (
|
||||
InfoSelfServiceLoginRoot ID = 1010000 + iota // 1010000
|
||||
InfoSelfServiceLogin // 1010001
|
||||
InfoSelfServiceLoginWith // 1010002
|
||||
InfoSelfServiceLoginReAuth // 1010003
|
||||
InfoSelfServiceLoginMFA // 1010004
|
||||
InfoSelfServiceLoginVerify // 1010005
|
||||
InfoSelfServiceLoginTOTPLabel // 1010006
|
||||
InfoLoginLookupLabel // 1010007
|
||||
InfoSelfServiceLoginWebAuthn // 1010008
|
||||
InfoLoginTOTP // 1010009
|
||||
InfoLoginLookup // 1010010
|
||||
InfoSelfServiceLoginContinueWebAuthn // 1010011
|
||||
InfoSelfServiceLoginWebAuthnPasswordless // 1010012
|
||||
InfoSelfServiceLoginContinue // 1010013
|
||||
InfoSelfServiceLoginCodeSent // 1010014
|
||||
InfoSelfServiceLoginCode // 1010015
|
||||
InfoSelfServiceLoginLink // 1010016
|
||||
InfoSelfServiceLoginAndLink // 1010017
|
||||
InfoSelfServiceLoginWithAndLink // 1010018
|
||||
InfoSelfServiceLoginCodeMFA // 1010019
|
||||
InfoSelfServiceLoginCodeMFAHint // 1010020
|
||||
InfoSelfServiceLoginPasskey // 1010021
|
||||
InfoSelfServiceLoginPassword // 1010022
|
||||
InfoSelfServiceLoginAAL2CodeAddress // 1010023
|
||||
InfoSelfServiceLoginDeviceAuthn // 1010024
|
||||
InfoSelfServiceLoginCodeSentForAuthenticatedUser // 1010025
|
||||
)
|
||||
|
||||
const (
|
||||
InfoSelfServiceLogout ID = 1020000 + iota
|
||||
)
|
||||
|
||||
const (
|
||||
InfoSelfServiceMFA ID = 1030000 + iota
|
||||
)
|
||||
|
||||
const (
|
||||
InfoSelfServiceRegistrationRoot ID = 1040000 + iota // 1040000
|
||||
InfoSelfServiceRegistration // 1040001
|
||||
InfoSelfServiceRegistrationWith // 1040002
|
||||
InfoSelfServiceRegistrationContinue // 1040003
|
||||
InfoSelfServiceRegistrationRegisterWebAuthn // 1040004
|
||||
InfoSelfServiceRegistrationEmailWithCodeSent // 1040005
|
||||
InfoSelfServiceRegistrationRegisterCode // 1040006
|
||||
InfoSelfServiceRegistrationRegisterPasskey // 1040007
|
||||
InfoSelfServiceRegistrationBack // 1040008
|
||||
InfoSelfServiceRegistrationChooseCredentials // 1040009
|
||||
)
|
||||
|
||||
const (
|
||||
InfoSelfServiceSettings ID = 1050000 + iota
|
||||
InfoSelfServiceSettingsUpdateSuccess
|
||||
InfoSelfServiceSettingsUpdateLinkOidc
|
||||
InfoSelfServiceSettingsUpdateUnlinkOidc
|
||||
InfoSelfServiceSettingsUpdateUnlinkTOTP
|
||||
InfoSelfServiceSettingsTOTPQRCode
|
||||
InfoSelfServiceSettingsTOTPSecret
|
||||
InfoSelfServiceSettingsRevealLookup
|
||||
InfoSelfServiceSettingsRegenerateLookup
|
||||
InfoSelfServiceSettingsLookupSecret
|
||||
InfoSelfServiceSettingsLookupSecretLabel
|
||||
InfoSelfServiceSettingsLookupConfirm
|
||||
InfoSelfServiceSettingsRegisterWebAuthn
|
||||
InfoSelfServiceSettingsRegisterWebAuthnDisplayName
|
||||
InfoSelfServiceSettingsLookupSecretUsed
|
||||
InfoSelfServiceSettingsLookupSecretList
|
||||
InfoSelfServiceSettingsDisableLookup
|
||||
InfoSelfServiceSettingsTOTPSecretLabel
|
||||
InfoSelfServiceSettingsRemoveWebAuthn
|
||||
InfoSelfServiceSettingsRegisterPasskey
|
||||
InfoSelfServiceSettingsRemovePasskey
|
||||
InfoSelfServiceSettingsRemoveDeviceAuthnKey
|
||||
InfoSelfServiceSettingsDeviceAuthnNonce
|
||||
InfoSelfServiceSettingsManagedByOrganization
|
||||
)
|
||||
|
||||
const (
|
||||
InfoSelfServiceRecovery ID = 1060000 + iota // 1060000
|
||||
InfoSelfServiceRecoverySuccessful // 1060001
|
||||
InfoSelfServiceRecoveryEmailSent // 1060002
|
||||
InfoSelfServiceRecoveryEmailWithCodeSent // 1060003
|
||||
InfoSelfServiceRecoveryMessageMaskedWithCodeSent // 1060004
|
||||
InfoSelfServiceRecoveryAskForFullAddress // 1060005
|
||||
InfoSelfServiceRecoveryAskToChooseAddress // 1060006
|
||||
InfoSelfServiceRecoveryBack // 1060007
|
||||
)
|
||||
|
||||
const (
|
||||
InfoNodeLabel ID = 1070000 + iota // 1070000
|
||||
InfoNodeLabelInputPassword // 1070001
|
||||
InfoNodeLabelGenerated // 1070002
|
||||
InfoNodeLabelSave // 1070003
|
||||
InfoNodeLabelID // 1070004
|
||||
InfoNodeLabelSubmit // 1070005
|
||||
InfoNodeLabelVerifyOTP // 1070006
|
||||
InfoNodeLabelEmail // 1070007
|
||||
InfoNodeLabelResendOTP // 1070008
|
||||
InfoNodeLabelContinue // 1070009
|
||||
InfoNodeLabelRecoveryCode // 1070010
|
||||
InfoNodeLabelVerificationCode // 1070011
|
||||
InfoNodeLabelRegistrationCode // 1070012
|
||||
InfoNodeLabelLoginCode // 1070013
|
||||
InfoNodeLabelLoginAndLinkCredential // 1070014
|
||||
InfoNodeLabelCaptcha // 1070015
|
||||
InfoNodeLabelRecoveryAddress // 1070016
|
||||
InfoNodeLabelPhoneNumber // 1070017
|
||||
InfoNodeLabelEmailOrPhone // 1070018
|
||||
)
|
||||
|
||||
const (
|
||||
InfoSelfServiceVerification ID = 1080000 + iota // 1080000
|
||||
InfoSelfServiceVerificationEmailSent // 1080001
|
||||
InfoSelfServiceVerificationSuccessful // 1080002
|
||||
InfoSelfServiceVerificationEmailWithCodeSent // 1080003
|
||||
InfoSelfServiceVerificationPhoneWithCodeSent // 1080004
|
||||
InfoSelfServiceVerificationPhoneSuccessful // 1080005
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorValidation ID = 4000000 + iota
|
||||
ErrorValidationGeneric
|
||||
ErrorValidationRequired
|
||||
ErrorValidationMinLength
|
||||
ErrorValidationInvalidFormat
|
||||
ErrorValidationPasswordPolicyViolationGeneric
|
||||
ErrorValidationInvalidCredentials
|
||||
ErrorValidationDuplicateCredentials
|
||||
ErrorValidationTOTPVerifierWrong
|
||||
ErrorValidationIdentifierMissing
|
||||
ErrorValidationAddressNotVerified
|
||||
ErrorValidationNoTOTPDevice
|
||||
ErrorValidationLookupAlreadyUsed
|
||||
ErrorValidationNoWebAuthnDevice
|
||||
ErrorValidationNoLookup
|
||||
ErrorValidationSuchNoWebAuthnUser
|
||||
ErrorValidationLookupInvalid
|
||||
ErrorValidationMaxLength
|
||||
ErrorValidationMinimum
|
||||
ErrorValidationExclusiveMinimum
|
||||
ErrorValidationMaximum
|
||||
ErrorValidationExclusiveMaximum
|
||||
ErrorValidationMultipleOf
|
||||
ErrorValidationMaxItems
|
||||
ErrorValidationMinItems
|
||||
ErrorValidationUniqueItems
|
||||
ErrorValidationWrongType
|
||||
ErrorValidationDuplicateCredentialsOnOIDCLink
|
||||
ErrorValidationDuplicateCredentialsWithHints
|
||||
ErrorValidationConst
|
||||
ErrorValidationConstGeneric
|
||||
ErrorValidationPasswordIdentifierTooSimilar
|
||||
ErrorValidationPasswordMinLength
|
||||
ErrorValidationPasswordMaxLength
|
||||
ErrorValidationPasswordTooManyBreaches
|
||||
ErrorValidationNoCodeUser
|
||||
ErrorValidationTraitsMismatch
|
||||
ErrorValidationAccountNotFound
|
||||
ErrorValidationCaptchaError
|
||||
ErrorValidationPasswordNewSameAsOld
|
||||
ErrorValidationEmail
|
||||
ErrorValidationPhone
|
||||
ErrorValidationNoDeviceAuthnDevice
|
||||
ErrorValidationWebAuthnVerifierWrong
|
||||
ErrorValidationDeviceAuthnVerifierWrong
|
||||
ErrorValidationDeviceAuthnRelaxedAttestationNoLongerValid
|
||||
ErrorValidationDeviceAuthnKeyReenrollmentRequired
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorValidationLogin ID = 4010000 + iota // 4010000
|
||||
ErrorValidationLoginFlowExpired // 4010001
|
||||
ErrorValidationLoginNoStrategyFound // 4010002
|
||||
ErrorValidationRegistrationNoStrategyFound // 4010003
|
||||
ErrorValidationSettingsNoStrategyFound // 4010004
|
||||
ErrorValidationRecoveryNoStrategyFound // 4010005
|
||||
ErrorValidationVerificationNoStrategyFound // 4010006
|
||||
ErrorValidationLoginRetrySuccess // 4010007
|
||||
ErrorValidationLoginCodeInvalidOrAlreadyUsed // 4010008
|
||||
ErrorValidationLoginLinkedCredentialsDoNotMatch // 4010009
|
||||
ErrorValidationLoginAddressUnknown // 4010010
|
||||
ErrorValidationIdentityDisabled // 4010011
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorValidationRegistration ID = 4040000 + iota
|
||||
ErrorValidationRegistrationFlowExpired // 4040001
|
||||
ErrorValidateionRegistrationRetrySuccess // 4040002
|
||||
ErrorValidationRegistrationCodeInvalidOrAlreadyUsed // 4040003
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorValidationSettings ID = 4050000 + iota
|
||||
ErrorValidationSettingsFlowExpired // 4050001
|
||||
ErrorValidationSettingsTooManyAddressChanges // 4050002
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorValidationRecovery ID = 4060000 + iota // 4060000
|
||||
ErrorValidationRecoveryRetrySuccess // 4060001
|
||||
ErrorValidationRecoveryStateFailure // 4060002
|
||||
ErrorValidationRecoveryMissingRecoveryToken // 4060003
|
||||
ErrorValidationRecoveryTokenInvalidOrAlreadyUsed // 4060004
|
||||
ErrorValidationRecoveryFlowExpired // 4060005
|
||||
ErrorValidationRecoveryCodeInvalidOrAlreadyUsed // 4060006
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorValidationVerification ID = 4070000 + iota // 4070000
|
||||
ErrorValidationVerificationTokenInvalidOrAlreadyUsed // 4070001
|
||||
ErrorValidationVerificationRetrySuccess // 4070002
|
||||
ErrorValidationVerificationStateFailure // 4070003
|
||||
ErrorValidationVerificationMissingVerificationToken // 4070004
|
||||
ErrorValidationVerificationFlowExpired // 4070005
|
||||
ErrorValidationVerificationCodeInvalidOrAlreadyUsed // 4070006
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorSystem ID = 5000000 + iota // 5000000
|
||||
ErrorSystemGeneric // 5000001
|
||||
ErrorSystemNoAuthenticationMethodsAvailable // 5000002
|
||||
ErrorSystemOrganizationNoSSOProvidersAvailable // 5000003
|
||||
)
|
||||
86
text/id_test.go
Normal file
86
text/id_test.go
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIDs(t *testing.T) {
|
||||
assert.Equal(t, 1010000, int(InfoSelfServiceLoginRoot))
|
||||
|
||||
assert.Equal(t, 1020000, int(InfoSelfServiceLogout))
|
||||
|
||||
assert.Equal(t, 1030000, int(InfoSelfServiceMFA))
|
||||
|
||||
assert.Equal(t, 1040000, int(InfoSelfServiceRegistrationRoot))
|
||||
assert.Equal(t, 1040001, int(InfoSelfServiceRegistration))
|
||||
|
||||
assert.Equal(t, 1050000, int(InfoSelfServiceSettings))
|
||||
assert.Equal(t, 1050001, int(InfoSelfServiceSettingsUpdateSuccess))
|
||||
|
||||
assert.Equal(t, 1060000, int(InfoSelfServiceRecovery))
|
||||
assert.Equal(t, 1060001, int(InfoSelfServiceRecoverySuccessful))
|
||||
assert.Equal(t, 1060002, int(InfoSelfServiceRecoveryEmailSent))
|
||||
assert.Equal(t, 1060003, int(InfoSelfServiceRecoveryEmailWithCodeSent))
|
||||
|
||||
assert.Equal(t, 1070000, int(InfoNodeLabel))
|
||||
assert.Equal(t, 1070001, int(InfoNodeLabelInputPassword))
|
||||
assert.Equal(t, 1070002, int(InfoNodeLabelGenerated))
|
||||
assert.Equal(t, 1070003, int(InfoNodeLabelSave))
|
||||
assert.Equal(t, 1070004, int(InfoNodeLabelID))
|
||||
assert.Equal(t, 1070005, int(InfoNodeLabelSubmit))
|
||||
assert.Equal(t, 1070006, int(InfoNodeLabelVerifyOTP))
|
||||
assert.Equal(t, 1070007, int(InfoNodeLabelEmail))
|
||||
assert.Equal(t, 1070008, int(InfoNodeLabelResendOTP))
|
||||
assert.Equal(t, 1070009, int(InfoNodeLabelContinue))
|
||||
assert.Equal(t, 1070010, int(InfoNodeLabelRecoveryCode))
|
||||
assert.Equal(t, 1070011, int(InfoNodeLabelVerificationCode))
|
||||
assert.Equal(t, 1070018, int(InfoNodeLabelEmailOrPhone))
|
||||
|
||||
assert.Equal(t, 1080000, int(InfoSelfServiceVerification))
|
||||
|
||||
assert.Equal(t, 4000000, int(ErrorValidation))
|
||||
assert.Equal(t, 4000001, int(ErrorValidationGeneric))
|
||||
assert.Equal(t, 4000002, int(ErrorValidationRequired))
|
||||
|
||||
assert.Equal(t, 4010000, int(ErrorValidationLogin))
|
||||
assert.Equal(t, 4010001, int(ErrorValidationLoginFlowExpired))
|
||||
|
||||
assert.Equal(t, 4040000, int(ErrorValidationRegistration))
|
||||
assert.Equal(t, 4040001, int(ErrorValidationRegistrationFlowExpired))
|
||||
|
||||
assert.Equal(t, 4050000, int(ErrorValidationSettings))
|
||||
assert.Equal(t, 4050001, int(ErrorValidationSettingsFlowExpired))
|
||||
|
||||
assert.Equal(t, 4060000, int(ErrorValidationRecovery))
|
||||
assert.Equal(t, 4060001, int(ErrorValidationRecoveryRetrySuccess))
|
||||
assert.Equal(t, 4060002, int(ErrorValidationRecoveryStateFailure))
|
||||
|
||||
assert.Equal(t, 4070000, int(ErrorValidationVerification))
|
||||
assert.Equal(t, 4070001, int(ErrorValidationVerificationTokenInvalidOrAlreadyUsed))
|
||||
|
||||
assert.Equal(t, 5000000, int(ErrorSystem))
|
||||
assert.Equal(t, 5000001, int(ErrorSystemGeneric))
|
||||
assert.Equal(t, 5000002, int(ErrorSystemNoAuthenticationMethodsAvailable))
|
||||
assert.Equal(t, 5000003, int(ErrorSystemOrganizationNoSSOProvidersAvailable))
|
||||
|
||||
assert.Equal(t, 4060006, int(ErrorValidationRecoveryCodeInvalidOrAlreadyUsed))
|
||||
assert.Equal(t, 4070006, int(ErrorValidationVerificationCodeInvalidOrAlreadyUsed))
|
||||
|
||||
assert.Equal(t, 1080000, int(InfoSelfServiceVerification))
|
||||
assert.Equal(t, 1080001, int(InfoSelfServiceVerificationEmailSent))
|
||||
assert.Equal(t, 1080002, int(InfoSelfServiceVerificationSuccessful))
|
||||
assert.Equal(t, 1080003, int(InfoSelfServiceVerificationEmailWithCodeSent))
|
||||
assert.Equal(t, 1080004, int(InfoSelfServiceVerificationPhoneWithCodeSent))
|
||||
assert.Equal(t, 1080005, int(InfoSelfServiceVerificationPhoneSuccessful))
|
||||
|
||||
assert.Equal(t, 1070015, int(InfoNodeLabelCaptcha))
|
||||
assert.Equal(t, 4000038, int(ErrorValidationCaptchaError))
|
||||
|
||||
assert.Equal(t, 4000040, int(ErrorValidationEmail))
|
||||
assert.Equal(t, 4000041, int(ErrorValidationPhone))
|
||||
}
|
||||
89
text/message.go
Normal file
89
text/message.go
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/ory/x/sqlxx"
|
||||
)
|
||||
|
||||
// swagger:model uiTexts
|
||||
type Messages []Message
|
||||
|
||||
func (h Messages) MarshalJSON() ([]byte, error) {
|
||||
if len(h) == 0 {
|
||||
return []byte("[]"), nil
|
||||
}
|
||||
|
||||
return json.Marshal([]Message(h))
|
||||
}
|
||||
|
||||
func (h *Messages) Scan(value interface{}) error {
|
||||
return sqlxx.JSONScan(h, value)
|
||||
}
|
||||
|
||||
func (h Messages) Value() (driver.Value, error) {
|
||||
if h == nil {
|
||||
return []byte("[]"), nil
|
||||
}
|
||||
return json.Marshal(h)
|
||||
}
|
||||
|
||||
func (h *Messages) Add(m *Message) Messages {
|
||||
*h = append(*h, *m)
|
||||
return *h
|
||||
}
|
||||
|
||||
func (h *Messages) Set(m *Message) Messages {
|
||||
*h = Messages{*m}
|
||||
return *h
|
||||
}
|
||||
|
||||
func (h *Messages) Clear() Messages {
|
||||
*h = *new(Messages)
|
||||
return *h
|
||||
}
|
||||
|
||||
// swagger:model uiText
|
||||
type Message struct {
|
||||
// The message ID.
|
||||
//
|
||||
// required: true
|
||||
ID ID `json:"id"`
|
||||
|
||||
// The message text. Written in american english.
|
||||
//
|
||||
// required: true
|
||||
Text string `json:"text"`
|
||||
|
||||
// The message type.
|
||||
//
|
||||
// required: true
|
||||
Type UITextType `json:"type"`
|
||||
|
||||
// The message's context. Useful when customizing messages.
|
||||
Context json.RawMessage `json:"context,omitempty" faker:"-"`
|
||||
}
|
||||
|
||||
func (m *Message) Scan(value interface{}) error {
|
||||
return sqlxx.JSONScan(m, value)
|
||||
}
|
||||
|
||||
func (m Message) Value() (driver.Value, error) {
|
||||
return json.Marshal(&m)
|
||||
}
|
||||
|
||||
func (m *Message) Error() string {
|
||||
return m.Text
|
||||
}
|
||||
|
||||
func (m *Message) Is(err error) bool {
|
||||
em, ok := err.(*Message)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return m.ID == em.ID
|
||||
}
|
||||
27
text/message_error.go
Normal file
27
text/message_error.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
// This file contains error IDs for all system errors / JSON errors
|
||||
|
||||
const (
|
||||
ErrIDNeedsPrivilegedSession = "session_refresh_required"
|
||||
ErrIDSelfServiceFlowExpired = "self_service_flow_expired"
|
||||
ErrIDSelfServiceFlowDisabled = "self_service_flow_disabled"
|
||||
ErrIDSelfServiceBrowserLocationChangeRequiredError = "browser_location_change_required"
|
||||
ErrIDSelfServiceFlowReplaced = "self_service_flow_replaced"
|
||||
|
||||
ErrIDAlreadyLoggedIn = "session_already_available"
|
||||
ErrIDAddressNotVerified = "session_verified_address_required"
|
||||
ErrIDSessionHasAALAlready = "session_aal_already_fulfilled"
|
||||
ErrIDSessionRequiredForHigherAAL = "session_aal1_required"
|
||||
ErrIDHigherAALRequired = "session_aal2_required"
|
||||
ErrIDNoActiveSession = "session_inactive"
|
||||
ErrIDRedirectURLNotAllowed = "self_service_flow_return_to_forbidden"
|
||||
ErrIDInitiatedBySomeoneElse = "security_identity_mismatch"
|
||||
|
||||
ErrIDIdentityDisabled = "identity_disabled"
|
||||
|
||||
ErrIDCSRF = "security_csrf_violation"
|
||||
)
|
||||
324
text/message_login.go
Normal file
324
text/message_login.go
Normal file
@@ -0,0 +1,324 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ory/x/clock"
|
||||
)
|
||||
|
||||
func NewInfoLoginReAuth() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginReAuth,
|
||||
Type: Info,
|
||||
Text: "Please confirm this action by verifying that it is you.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoLoginMFA() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginMFA,
|
||||
Type: Info,
|
||||
Text: "Please complete the second authentication challenge.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoLoginWebAuthnPasswordless() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginWebAuthnPasswordless,
|
||||
Type: Info,
|
||||
Text: "Prepare your WebAuthn device (e.g. security key, biometrics scanner, ...) and press continue.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoLoginTOTPLabel() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginTOTPLabel,
|
||||
Type: Info,
|
||||
Text: "Authentication code",
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoLoginLookupLabel() *Message {
|
||||
return &Message{
|
||||
ID: InfoLoginLookupLabel,
|
||||
Type: Info,
|
||||
Text: "Backup recovery code",
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoLogin() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLogin,
|
||||
Text: "Sign in",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoLoginLinkMessage(dupIdentifier, provider, newLoginURL string, availableCredentials, availableProviders []string) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginLink,
|
||||
Type: Info,
|
||||
Text: fmt.Sprintf(
|
||||
"You tried to sign in with %q, but that email is already used by another account. Sign in to your account with one of the options below to add your account %[1]q at %q as another way to sign in.",
|
||||
dupIdentifier,
|
||||
provider,
|
||||
),
|
||||
Context: context(map[string]any{
|
||||
"duplicateIdentifier": dupIdentifier,
|
||||
"provider": provider,
|
||||
"newLoginUrl": newLoginURL,
|
||||
"duplicate_identifier": dupIdentifier,
|
||||
"new_login_url": newLoginURL,
|
||||
"available_credential_types": availableCredentials,
|
||||
"available_providers": availableProviders,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoLoginAndLink() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginAndLink,
|
||||
Text: "Sign in and link",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoLoginTOTP() *Message {
|
||||
return &Message{
|
||||
ID: InfoLoginTOTP,
|
||||
Text: "Use Authenticator",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoLoginPassword() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginPassword,
|
||||
Text: "Sign in with password",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoLoginLookup() *Message {
|
||||
return &Message{
|
||||
ID: InfoLoginLookup,
|
||||
Text: "Use backup recovery code",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoLoginVerify() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginVerify,
|
||||
Text: "Verify",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoLoginWith(provider string, providerId string) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginWith,
|
||||
Text: fmt.Sprintf("Sign in with %s", provider),
|
||||
Type: Info,
|
||||
Context: context(map[string]any{
|
||||
"provider": provider,
|
||||
"provider_id": providerId,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoLoginWithAndLink(provider string) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginWithAndLink,
|
||||
Text: fmt.Sprintf("Confirm with %s", provider),
|
||||
Type: Info,
|
||||
Context: context(map[string]any{
|
||||
"provider": provider,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationLoginFlowExpired(c clock.Clock, expiredAt time.Time) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationLoginFlowExpired,
|
||||
Text: fmt.Sprintf("The login flow expired %.2f minutes ago, please try again.", c.Now().Sub(expiredAt).Minutes()),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"expired_at": expiredAt,
|
||||
"expired_at_unix": expiredAt.Unix(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationLoginNoStrategyFound() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationLoginNoStrategyFound,
|
||||
Text: "Could not find a strategy to log you in with. Did you fill out the form correctly?",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationRegistrationNoStrategyFound() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationRegistrationNoStrategyFound,
|
||||
Text: "Could not find a strategy to sign you up with. Did you fill out the form correctly?",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationSettingsNoStrategyFound() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationSettingsNoStrategyFound,
|
||||
Text: "Could not find a strategy to update your settings. Did you fill out the form correctly?",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationRecoveryNoStrategyFound() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationRecoveryNoStrategyFound,
|
||||
Text: "Could not find a strategy to recover your account with. Did you fill out the form correctly?",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationVerificationNoStrategyFound() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationVerificationNoStrategyFound,
|
||||
Text: "Could not find a strategy to verify your account with. Did you fill out the form correctly?",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceLoginWebAuthn() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginWebAuthn,
|
||||
Text: "Sign in with a hardware key",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceLoginDeviceAuthn() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginDeviceAuthn,
|
||||
Text: "Sign in with a hardware key",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceLoginPasskey() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginPasskey,
|
||||
Text: "Sign in with passkey",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceContinueLoginWebAuthn() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginContinueWebAuthn,
|
||||
Text: "Sign in with a hardware key",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceLoginContinue() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginContinue,
|
||||
Text: "Continue",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewLoginCodeSent() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginCodeSent,
|
||||
Type: Info,
|
||||
Text: "A code was sent to the address you provided. If you didn't receive it, please check the spelling of the address and try again.",
|
||||
}
|
||||
}
|
||||
|
||||
// NewLoginCodeSentForAuthenticatedUser is shown on refresh and second factor
|
||||
// login flows where the address is bound to the authenticated identity rather
|
||||
// than typed by the user. The wording avoids the inaccurate "address you
|
||||
// provided" phrasing and the unhelpful "check the spelling" guidance, since
|
||||
// the user cannot change the recipient mid-flow.
|
||||
func NewLoginCodeSentForAuthenticatedUser() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginCodeSentForAuthenticatedUser,
|
||||
Type: Info,
|
||||
Text: "A code was sent to your address. If you didn't receive it, please try again.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationLoginCodeInvalidOrAlreadyUsed() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationLoginCodeInvalidOrAlreadyUsed,
|
||||
Text: "The login code is invalid or has already been used. Please try again.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationLoginRetrySuccessful() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationLoginRetrySuccess,
|
||||
Type: Error,
|
||||
Text: "The request was already completed successfully and can not be retried.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceLoginCode() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginCode,
|
||||
Type: Info,
|
||||
Text: "Send sign in code",
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationLoginLinkedCredentialsDoNotMatch() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationLoginLinkedCredentialsDoNotMatch,
|
||||
Text: "Linked credentials do not match.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationAddressUnknown() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationLoginAddressUnknown,
|
||||
Text: "The address you entered does not match any known addresses in the current account.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceLoginCodeMFA() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginCodeMFA,
|
||||
Type: Info,
|
||||
Text: "Request code to continue",
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceLoginAAL2CodeAddress(channel string, to string) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceLoginAAL2CodeAddress,
|
||||
Type: Info,
|
||||
Text: fmt.Sprintf("Send code to %s", to),
|
||||
Context: context(map[string]any{
|
||||
"address": to,
|
||||
"channel": channel,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationIdentityDisabled() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationIdentityDisabled,
|
||||
Text: "This account has been disabled. Please contact support for assistance.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
136
text/message_node.go
Normal file
136
text/message_node.go
Normal file
@@ -0,0 +1,136 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
func NewInfoNodeLabelVerifyOTP() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelVerifyOTP,
|
||||
Text: "Verify code",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeLabelVerificationCode() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelVerificationCode,
|
||||
Text: "Verification code",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeLabelRecoveryCode() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelRecoveryCode,
|
||||
Text: "Recovery code",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeLabelRegistrationCode() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelRegistrationCode,
|
||||
Text: "Registration code",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeLabelLoginCode() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelLoginCode,
|
||||
Text: "Login code",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeInputPassword() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelInputPassword,
|
||||
Text: "Password",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeLabelGenerated(title string, name string) *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelGenerated,
|
||||
Text: title,
|
||||
Type: Info,
|
||||
Context: context(map[string]any{
|
||||
"title": title,
|
||||
"name": name,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeLabelSave() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelSave,
|
||||
Text: "Save",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeLabelSubmit() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelSubmit,
|
||||
Text: "Submit",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeLabelContinue() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelContinue,
|
||||
Text: "Continue",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeLabelID() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelID,
|
||||
Text: "ID",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeInputEmail() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelEmail,
|
||||
Text: "Email",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeInputPhoneNumber() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelPhoneNumber,
|
||||
Text: "Phone number",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeInputEmailOrPhone() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelEmailOrPhone,
|
||||
Text: "Email or phone number",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeResendOTP() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelResendOTP,
|
||||
Text: "Resend code",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoNodeLoginAndLinkCredential() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelLoginAndLinkCredential,
|
||||
Text: "Login and link credential",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
128
text/message_recovery.go
Normal file
128
text/message_recovery.go
Normal file
@@ -0,0 +1,128 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ory/x/clock"
|
||||
)
|
||||
|
||||
func NewErrorValidationRecoveryFlowExpired(c clock.Clock, expiredAt time.Time) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationRecoveryFlowExpired,
|
||||
Text: fmt.Sprintf("The recovery flow expired %.2f minutes ago, please try again.", c.Now().Sub(expiredAt).Minutes()),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"expired_at": expiredAt,
|
||||
"expired_at_unix": expiredAt.Unix(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewRecoverySuccessful(c clock.Clock, privilegedSessionExpiresAt time.Time) *Message {
|
||||
hasLeft := privilegedSessionExpiresAt.Sub(c.Now())
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRecoverySuccessful,
|
||||
Type: Success,
|
||||
Text: fmt.Sprintf("You successfully recovered your account. Please change your password or set up an alternative login method (e.g. social sign in) within the next %.2f minutes.", hasLeft.Minutes()),
|
||||
Context: context(map[string]any{
|
||||
"privilegedSessionExpiresAt": privilegedSessionExpiresAt,
|
||||
"privileged_session_expires_at": privilegedSessionExpiresAt,
|
||||
"privileged_session_expires_at_unix": privilegedSessionExpiresAt.Unix(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewRecoveryEmailSent() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRecoveryEmailSent,
|
||||
Type: Info,
|
||||
Text: "An email containing a recovery link has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewRecoveryEmailWithCodeSent() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRecoveryEmailWithCodeSent,
|
||||
Type: Info,
|
||||
Text: "An email containing a recovery code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewRecoveryAskAnyRecoveryAddress() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelRecoveryAddress,
|
||||
Text: "Recovery address",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewRecoveryCodeRecoverySelectAddressSent(maskedAddress string) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRecoveryMessageMaskedWithCodeSent,
|
||||
Type: Info,
|
||||
Text: fmt.Sprintf("A recovery code has been sent to %s. If you have not received it, check the spelling of the address and make sure to use the address you registered with.", maskedAddress),
|
||||
Context: context(map[string]any{
|
||||
"masked_address": maskedAddress,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewRecoveryAskForFullAddress() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRecoveryAskForFullAddress,
|
||||
Type: Info,
|
||||
Text: "Recover access to your account by providing your recovery address in full.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewRecoveryAskToChooseAddress() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRecoveryAskToChooseAddress,
|
||||
Type: Info,
|
||||
Text: "How do you want to recover your account?",
|
||||
}
|
||||
}
|
||||
|
||||
func NewRecoveryBack() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRecoveryBack,
|
||||
Type: Info,
|
||||
Text: "Back",
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationRecoveryTokenInvalidOrAlreadyUsed() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationRecoveryTokenInvalidOrAlreadyUsed,
|
||||
Text: "The recovery token is invalid or has already been used. Please retry the flow.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationRecoveryCodeInvalidOrAlreadyUsed() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationRecoveryCodeInvalidOrAlreadyUsed,
|
||||
Text: "The recovery code is invalid or has already been used. Please try again.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationRecoveryRetrySuccess() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationRecoveryRetrySuccess,
|
||||
Text: "The request was already completed successfully and can not be retried.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationRecoveryStateFailure() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationRecoveryStateFailure,
|
||||
Text: "The recovery flow reached a failure state and must be retried.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
115
text/message_registration.go
Normal file
115
text/message_registration.go
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ory/x/clock"
|
||||
)
|
||||
|
||||
func NewInfoRegistration() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRegistration,
|
||||
Text: "Sign up",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoRegistrationWith(provider string, providerID string) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRegistrationWith,
|
||||
Text: fmt.Sprintf("Sign up with %s", provider),
|
||||
Type: Info,
|
||||
Context: context(map[string]any{
|
||||
"provider": provider,
|
||||
"provider_id": providerID,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoRegistrationContinue() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRegistrationContinue,
|
||||
Text: "Continue",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoRegistrationBack() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRegistrationBack,
|
||||
Text: "Back",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceChooseCredentials() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRegistrationChooseCredentials,
|
||||
Text: "Please choose a credential to authenticate yourself with.",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationRegistrationFlowExpired(c clock.Clock, expiredAt time.Time) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationRegistrationFlowExpired,
|
||||
Text: fmt.Sprintf("The registration flow expired %.2f minutes ago, please try again.", c.Now().Sub(expiredAt).Minutes()),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"expired_at": expiredAt,
|
||||
"expired_at_unix": expiredAt.Unix(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceRegistrationRegisterWebAuthn() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRegistrationRegisterWebAuthn,
|
||||
Text: "Sign up with security key",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceRegistrationRegisterPasskey() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRegistrationRegisterPasskey,
|
||||
Text: "Sign up with passkey",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewRegistrationEmailWithCodeSent() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRegistrationEmailWithCodeSent,
|
||||
Type: Info,
|
||||
Text: "A code has been sent to the address(es) you provided. If you have not received a message, check the spelling of the address and retry the registration.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationRegistrationCodeInvalidOrAlreadyUsed() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationRegistrationCodeInvalidOrAlreadyUsed,
|
||||
Text: "The registration code is invalid or has already been used. Please try again.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationRegistrationRetrySuccessful() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidateionRegistrationRetrySuccess,
|
||||
Type: Error,
|
||||
Text: "The request was already completed successfully and can not be retried.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceRegistrationRegisterCode() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceRegistrationRegisterCode,
|
||||
Text: "Send sign up code",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
227
text/message_settings.go
Normal file
227
text/message_settings.go
Normal file
@@ -0,0 +1,227 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ory/x/clock"
|
||||
)
|
||||
|
||||
func NewErrorValidationSettingsFlowExpired(c clock.Clock, expiredAt time.Time) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationSettingsFlowExpired,
|
||||
Text: fmt.Sprintf("The settings flow expired %.2f minutes ago, please try again.", c.Now().Sub(expiredAt).Minutes()),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"expired_at": expiredAt,
|
||||
"expired_at_unix": expiredAt.Unix(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationSettingsTooManyAddressChanges() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationSettingsTooManyAddressChanges,
|
||||
Text: "You can only change one address at a time. Please update each address separately.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsTOTPQRCode() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsTOTPQRCode,
|
||||
Text: "Authenticator app QR code",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsTOTPSecret(secret string) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsTOTPSecret,
|
||||
Text: secret,
|
||||
Type: Info,
|
||||
Context: context(map[string]any{
|
||||
"secret": secret,
|
||||
}),
|
||||
}
|
||||
}
|
||||
func NewInfoSelfServiceSettingsTOTPSecretLabel() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsTOTPSecretLabel,
|
||||
Text: "This is your authenticator app secret. Use it if you can not scan the QR code.",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsUpdateSuccess() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsUpdateSuccess,
|
||||
Text: "Your changes have been saved!",
|
||||
Type: Success,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsUpdateUnlinkTOTP() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsUpdateUnlinkTOTP,
|
||||
Text: "Unlink TOTP Authenticator App",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsRevealLookup() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsRevealLookup,
|
||||
Text: "Reveal backup recovery codes",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsRegenerateLookup() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsRegenerateLookup,
|
||||
Text: "Generate new backup recovery codes",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsDisableLookup() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsDisableLookup,
|
||||
Text: "Disable this method",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsLookupConfirm() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsLookupConfirm,
|
||||
Text: "Confirm backup recovery codes",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsLookupSecretList(secrets []string, raw any) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsLookupSecretList,
|
||||
Text: strings.Join(secrets, ", "),
|
||||
Type: Info,
|
||||
Context: context(map[string]any{
|
||||
"secrets": raw,
|
||||
}),
|
||||
}
|
||||
}
|
||||
func NewInfoSelfServiceSettingsLookupSecret(secret string) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsLookupSecret,
|
||||
Text: secret,
|
||||
Type: Info,
|
||||
Context: context(map[string]any{
|
||||
"secret": secret,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsLookupSecretUsed(usedAt time.Time) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsLookupSecretUsed,
|
||||
Text: fmt.Sprintf("Secret was used at %s", usedAt),
|
||||
Type: Info,
|
||||
Context: context(map[string]any{
|
||||
"used_at": usedAt,
|
||||
"used_at_unix": usedAt.Unix(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsLookupSecretsLabel() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsLookupSecretLabel,
|
||||
Text: "These are your back up recovery codes. Please keep them in a safe place!",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsUpdateLinkOIDC(provider string) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsUpdateLinkOidc,
|
||||
Text: fmt.Sprintf("Link %s", provider),
|
||||
Type: Info,
|
||||
Context: context(map[string]any{
|
||||
"provider": provider,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsUpdateUnlinkOIDC(provider string) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsUpdateUnlinkOidc,
|
||||
Text: fmt.Sprintf("Unlink %s", provider),
|
||||
Type: Info,
|
||||
Context: context(map[string]any{
|
||||
"provider": provider,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsRegisterWebAuthn() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsRegisterWebAuthn,
|
||||
Text: "Add security key",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsRegisterPasskey() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsRegisterPasskey,
|
||||
Text: "Add passkey",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceRegisterWebAuthnDisplayName() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsRegisterWebAuthnDisplayName,
|
||||
Text: "Name of the security key",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceRemoveWebAuthn(name string, createdAt time.Time) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsRemoveWebAuthn,
|
||||
Text: fmt.Sprintf("Remove security key \"%s\"", name),
|
||||
Type: Info,
|
||||
Context: context(map[string]any{
|
||||
"display_name": name,
|
||||
"added_at": createdAt,
|
||||
"added_at_unix": createdAt.Unix(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceRemovePasskey(name string, createdAt time.Time) *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsRemovePasskey,
|
||||
Text: fmt.Sprintf("Remove passkey \"%s\"", name),
|
||||
Type: Info,
|
||||
Context: context(map[string]any{
|
||||
"display_name": name,
|
||||
"added_at": createdAt,
|
||||
"added_at_unix": createdAt.Unix(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceSettingsManagedByOrganization() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceSettingsManagedByOrganization,
|
||||
Text: "Your account is managed by your organization. To change these settings, contact your organization administrator.",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
39
text/message_system.go
Normal file
39
text/message_system.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
func NewErrorSystemGeneric(reason string) *Message {
|
||||
return &Message{
|
||||
ID: ErrorSystemGeneric,
|
||||
Text: reason,
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"reason": reason,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorSystemNoAuthenticationMethodsAvailable() *Message {
|
||||
return &Message{
|
||||
ID: ErrorSystemNoAuthenticationMethodsAvailable,
|
||||
Text: "No authentication methods are available. Please contact the system administrator.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorSystemOrganizationNoSSOProvidersAvailable() *Message {
|
||||
return &Message{
|
||||
ID: ErrorSystemOrganizationNoSSOProvidersAvailable,
|
||||
Text: "Your organization requires SSO authentication, but no SSO provider is configured. Please contact the system administrator.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCaptchaContainerMessage() *Message {
|
||||
return &Message{
|
||||
ID: InfoNodeLabelCaptcha,
|
||||
Text: "Please complete the captcha challenge to continue.",
|
||||
Type: Info,
|
||||
}
|
||||
}
|
||||
52
text/message_test.go
Normal file
52
text/message_test.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMessage(t *testing.T) {
|
||||
expected := &Message{ID: InfoSelfServiceSettingsUpdateSuccess, Text: "foo", Type: Info}
|
||||
|
||||
v, err := expected.Value()
|
||||
require.NoError(t, err)
|
||||
|
||||
var actual Message
|
||||
require.NoError(t, actual.Scan(v))
|
||||
|
||||
assert.EqualValues(t, expected, &actual, v)
|
||||
}
|
||||
|
||||
func TestNewErrorValidationDuplicateCredentialsWithHints(t *testing.T) {
|
||||
t.Run("title-cases real provider names", func(t *testing.T) {
|
||||
msg := NewErrorValidationDuplicateCredentialsWithHints(nil, []string{"google", "github"}, "user@example.com")
|
||||
assert.Contains(t, msg.Text, "Google, Github")
|
||||
})
|
||||
|
||||
t.Run("preserves placeholder templates without title-casing", func(t *testing.T) {
|
||||
msg := NewErrorValidationDuplicateCredentialsWithHints(
|
||||
[]string{"{available_credential_types_list}"},
|
||||
[]string{"{available_oidc_providers_list}"},
|
||||
"{credential_identifier_hint}",
|
||||
)
|
||||
assert.Contains(t, msg.Text, "{available_oidc_providers_list}")
|
||||
assert.NotContains(t, msg.Text, "{Available_oidc_providers_list}")
|
||||
})
|
||||
}
|
||||
|
||||
func TestMessages(t *testing.T) {
|
||||
expected := Messages{{ID: InfoSelfServiceSettingsUpdateSuccess, Text: "foo", Type: Info}}
|
||||
|
||||
v, err := expected.Value()
|
||||
require.NoError(t, err)
|
||||
|
||||
var actual Messages
|
||||
require.NoError(t, actual.Scan(v))
|
||||
|
||||
assert.EqualValues(t, expected, actual, v)
|
||||
}
|
||||
511
text/message_validation.go
Normal file
511
text/message_validation.go
Normal file
@@ -0,0 +1,511 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ory/x/stringslice"
|
||||
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func NewValidationErrorGeneric(reason string) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationGeneric,
|
||||
Text: reason,
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"reason": reason,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewValidationErrorRequired(missing string) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationRequired,
|
||||
Text: fmt.Sprintf("Property %s is missing.", missing),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"property": missing,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationMinLength(minLength, actualLength int) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationMinLength,
|
||||
Text: fmt.Sprintf("length must be >= %d, but got %d", minLength, actualLength),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"min_length": minLength,
|
||||
"actual_length": actualLength,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationMaxLength(maxLength, actualLength int) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationMaxLength,
|
||||
Text: fmt.Sprintf("length must be <= %d, but got %d", maxLength, actualLength),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"max_length": maxLength,
|
||||
"actual_length": actualLength,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationInvalidFormat(pattern string) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationInvalidFormat,
|
||||
Text: fmt.Sprintf("does not match pattern %q", pattern),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"pattern": pattern,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationMinimum(minimum, actual float64) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationMinimum,
|
||||
Text: fmt.Sprintf("must be >= %v but found %v", minimum, actual),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"minimum": minimum,
|
||||
"actual": actual,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationExclusiveMinimum(minimum, actual float64) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationExclusiveMinimum,
|
||||
Text: fmt.Sprintf("must be > %v but found %v", minimum, actual),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"minimum": minimum,
|
||||
"actual": actual,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationMaximum(maximum, actual float64) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationMaximum,
|
||||
Text: fmt.Sprintf("must be <= %v but found %v", maximum, actual),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"maximum": maximum,
|
||||
"actual": actual,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationExclusiveMaximum(maximum, actual float64) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationExclusiveMaximum,
|
||||
Text: fmt.Sprintf("must be < %v but found %v", maximum, actual),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"maximum": maximum,
|
||||
"actual": actual,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationMultipleOf(base, actual float64) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationMultipleOf,
|
||||
Text: fmt.Sprintf("%v not multipleOf %v", actual, base),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"base": base,
|
||||
"actual": actual,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationMaxItems(maxItems, actualItems int) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationMaxItems,
|
||||
Text: fmt.Sprintf("maximum %d items allowed, but found %d items", maxItems, actualItems),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"max_items": maxItems,
|
||||
"actual_items": actualItems,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationMinItems(minItems, actualItems int) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationMinItems,
|
||||
Text: fmt.Sprintf("minimum %d items allowed, but found %d items", minItems, actualItems),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"min_items": minItems,
|
||||
"actual_items": actualItems,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationUniqueItems(indexA, indexB int) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationUniqueItems,
|
||||
Text: fmt.Sprintf("items at index %d and %d are equal", indexA, indexB),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"index_a": indexA,
|
||||
"index_b": indexB,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationWrongType(allowedTypes []string, actualType string) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationWrongType,
|
||||
Text: fmt.Sprintf("expected %s, but got %s", strings.Join(allowedTypes, " or "), actualType),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"allowed_types": allowedTypes,
|
||||
"actual_type": actualType,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationConst(expected any) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationConst,
|
||||
Text: fmt.Sprintf("must be equal to constant %v", expected),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"expected": expected,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationConstGeneric() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationConstGeneric,
|
||||
Text: "const failed",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationEmail(value string) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationEmail,
|
||||
Text: "Enter a valid email address",
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"value": value,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationPhone(value string) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationPhone,
|
||||
Text: "Enter a valid phone number",
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"value": value,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationPasswordPolicyViolationGeneric(reason string) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationPasswordPolicyViolationGeneric,
|
||||
Text: fmt.Sprintf("The password can not be used because %s.", reason),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"reason": reason,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationPasswordIdentifierTooSimilar() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationPasswordIdentifierTooSimilar,
|
||||
Text: "The password can not be used because it is too similar to the identifier.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationPasswordMinLength(minLength, actualLength int) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationPasswordMinLength,
|
||||
Text: fmt.Sprintf("The password must be at least %d characters long, but got %d.", minLength, actualLength),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"min_length": minLength,
|
||||
"actual_length": actualLength,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationPasswordMaxLength(maxLength, actualLength int) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationPasswordMaxLength,
|
||||
Text: fmt.Sprintf("The password must be at most %d characters long, but got %d.", maxLength, actualLength),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"max_length": maxLength,
|
||||
"actual_length": actualLength,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationPasswordNewSameAsOld() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationPasswordNewSameAsOld,
|
||||
Text: "The new password must be different from the old password.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationPasswordTooManyBreaches(breaches int64) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationPasswordTooManyBreaches,
|
||||
Text: "The password has been found in data breaches and must no longer be used.",
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"breaches": breaches,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationInvalidCredentials() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationInvalidCredentials,
|
||||
Text: "The provided credentials are invalid, check for spelling mistakes in your password or username, email address, or phone number.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationAccountNotFound() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationAccountNotFound,
|
||||
Text: "This account does not exist or has no login method configured.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationDuplicateCredentials() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationDuplicateCredentials,
|
||||
Text: "An account with the same identifier (email, phone, username, ...) exists already.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationDuplicateCredentialsWithHints(availableCredentialTypes []string, availableOIDCProviders []string, credentialIdentifierHint string) *Message {
|
||||
identifier := credentialIdentifierHint
|
||||
if identifier == "" {
|
||||
identifier = "an email, phone, or username"
|
||||
}
|
||||
oidcProviders := make([]string, 0, len(availableOIDCProviders))
|
||||
for _, provider := range availableOIDCProviders {
|
||||
if strings.ContainsAny(provider, "{}") {
|
||||
oidcProviders = append(oidcProviders, provider)
|
||||
} else {
|
||||
oidcProviders = append(oidcProviders, cases.Title(language.English).String(provider))
|
||||
}
|
||||
}
|
||||
|
||||
reason := fmt.Sprintf("You tried signing in with %s which is already in use by another account.", identifier)
|
||||
if len(availableCredentialTypes) > 0 {
|
||||
humanReadable := make([]string, 0, len(availableCredentialTypes))
|
||||
for _, cred := range availableCredentialTypes {
|
||||
switch cred {
|
||||
case "password":
|
||||
humanReadable = append(humanReadable, "your password")
|
||||
case "oidc", "saml":
|
||||
humanReadable = append(humanReadable, "social sign in")
|
||||
case "webauthn":
|
||||
humanReadable = append(humanReadable, "your passkey or a security key")
|
||||
case "passkey":
|
||||
humanReadable = append(humanReadable, "your passkey")
|
||||
}
|
||||
}
|
||||
if len(humanReadable) == 0 {
|
||||
// show at least some hint
|
||||
// also our example message generation tool runs into this case
|
||||
humanReadable = append(humanReadable, availableCredentialTypes...)
|
||||
}
|
||||
|
||||
humanReadable = stringslice.Unique(humanReadable)
|
||||
|
||||
// Final format: "You can sign in using foo, bar, or baz."
|
||||
if len(humanReadable) > 1 {
|
||||
humanReadable[len(humanReadable)-1] = "or " + humanReadable[len(humanReadable)-1]
|
||||
}
|
||||
if len(humanReadable) > 0 {
|
||||
reason += fmt.Sprintf(" You can sign in using %s.", strings.Join(humanReadable, ", "))
|
||||
}
|
||||
}
|
||||
if len(oidcProviders) > 0 {
|
||||
reason += fmt.Sprintf(" You can sign in using one of the following social sign in providers: %s.", strings.Join(oidcProviders, ", "))
|
||||
}
|
||||
|
||||
return &Message{
|
||||
ID: ErrorValidationDuplicateCredentialsWithHints,
|
||||
Text: reason,
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"available_credential_types": availableCredentialTypes,
|
||||
"available_oidc_providers": availableOIDCProviders,
|
||||
"credential_identifier_hint": credentialIdentifierHint,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationDuplicateCredentialsOnOIDCLink() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationDuplicateCredentialsOnOIDCLink,
|
||||
Text: "An account with the same identifier (email, phone, username, ...) exists already. " +
|
||||
"Please sign in to your existing account to link your social profile.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationTOTPVerifierWrong() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationTOTPVerifierWrong,
|
||||
Text: "The provided authentication code is invalid, please try again.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationWebAuthnVerifierWrong() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationWebAuthnVerifierWrong,
|
||||
Text: "The provided web authn login is invalid, please try again.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
func NewErrorValidationDeviceAuthnVerifierWrong() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationDeviceAuthnVerifierWrong,
|
||||
Text: "The provided DeviceAuthn signature is invalid.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationDeviceAuthnRelaxedAttestationNoLongerValid() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationDeviceAuthnRelaxedAttestationNoLongerValid,
|
||||
Text: "This DeviceAuthn key can no longer be used because relaxed attestation is expired or disabled. Please enroll your device again.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationDeviceAuthnKeyReenrollmentRequired() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationDeviceAuthnKeyReenrollmentRequired,
|
||||
Text: "This DeviceAuthn key was enrolled before user verification was introduced and can no longer be used. Please enroll your device again.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationLookupAlreadyUsed() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationLookupAlreadyUsed,
|
||||
Text: "This backup recovery code has already been used.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationLookupInvalid() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationLookupInvalid,
|
||||
Text: "The backup recovery code is not valid.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationIdentifierMissing() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationIdentifierMissing,
|
||||
Text: "Could not find any login identifiers. Did you forget to set them? This could also be caused by a server misconfiguration.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationAddressNotVerified() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationAddressNotVerified,
|
||||
Text: "Account not active yet. Did you forget to verify your email address?",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationNoTOTPDevice() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationNoTOTPDevice,
|
||||
Text: "You have no TOTP device set up.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationNoLookup() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationNoLookup,
|
||||
Text: "You have no backup recovery codes set up.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationNoWebAuthnDevice() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationNoWebAuthnDevice,
|
||||
Text: "You have no WebAuthn device set up.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationSuchNoWebAuthnUser() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationSuchNoWebAuthnUser,
|
||||
Text: "This account does not exist or has no security key set up.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationNoDeviceAuthnDevice() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationNoDeviceAuthnDevice,
|
||||
Text: "You have no DeviceAuthn device set up.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationNoCodeUser() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationNoCodeUser,
|
||||
Text: "This account does not exist or has not setup sign in with code.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationTraitsMismatch() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationTraitsMismatch,
|
||||
Text: "The provided traits do not match the traits previously associated with this flow.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorCaptchaFailed() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationCaptchaError,
|
||||
Text: "Captcha verification failed, please try again.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
105
text/message_verification.go
Normal file
105
text/message_verification.go
Normal file
@@ -0,0 +1,105 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ory/x/clock"
|
||||
)
|
||||
|
||||
func NewErrorValidationVerificationFlowExpired(c clock.Clock, expiredAt time.Time) *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationVerificationFlowExpired,
|
||||
Text: fmt.Sprintf("The verification flow expired %.2f minutes ago, please try again.", c.Now().Sub(expiredAt).Minutes()),
|
||||
Type: Error,
|
||||
Context: context(map[string]any{
|
||||
"expired_at": expiredAt,
|
||||
"expired_at_unix": expiredAt.Unix(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceVerificationSuccessful() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceVerificationSuccessful,
|
||||
Type: Success,
|
||||
Text: "You successfully verified your email address.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewInfoSelfServiceVerificationPhoneSuccessful() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceVerificationPhoneSuccessful,
|
||||
Type: Success,
|
||||
Text: "You successfully verified your phone number.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewVerificationEmailSent() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceVerificationEmailSent,
|
||||
Type: Info,
|
||||
Text: "An email containing a verification link has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationVerificationTokenInvalidOrAlreadyUsed() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationVerificationTokenInvalidOrAlreadyUsed,
|
||||
Text: "The verification token is invalid or has already been used. Please retry the flow.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationVerificationRetrySuccess() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationVerificationRetrySuccess,
|
||||
Text: "The request was already completed successfully and can not be retried.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationVerificationStateFailure() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationVerificationStateFailure,
|
||||
Text: "The verification flow reached a failure state and must be retried.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewErrorValidationVerificationCodeInvalidOrAlreadyUsed() *Message {
|
||||
return &Message{
|
||||
ID: ErrorValidationVerificationCodeInvalidOrAlreadyUsed,
|
||||
Text: "The verification code is invalid or has already been used. Please try again.",
|
||||
Type: Error,
|
||||
}
|
||||
}
|
||||
|
||||
func NewVerificationEmailWithCodeSent() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceVerificationEmailWithCodeSent,
|
||||
Type: Info,
|
||||
Text: "An email containing a verification code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and make sure to use the address you registered with.",
|
||||
}
|
||||
}
|
||||
|
||||
func NewVerificationPhoneWithCodeSent() *Message {
|
||||
return &Message{
|
||||
ID: InfoSelfServiceVerificationPhoneWithCodeSent,
|
||||
Type: Info,
|
||||
Text: "A text message containing a verification code has been sent to the phone number you provided. If you have not received a text message, check the spelling of the number and make sure to use the number you registered with.",
|
||||
}
|
||||
}
|
||||
|
||||
// VerificationCodeSentMessage returns the "code has been sent" message for the
|
||||
// channel the code was delivered over. SMS verifications get the phone wording;
|
||||
// every other channel falls back to the email wording.
|
||||
func VerificationCodeSentMessage(via string) *Message {
|
||||
if via == "sms" {
|
||||
return NewVerificationPhoneWithCodeSent()
|
||||
}
|
||||
return NewVerificationEmailWithCodeSent()
|
||||
}
|
||||
45
text/message_verification_test.go
Normal file
45
text/message_verification_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright © 2026 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/ory/x/clock"
|
||||
)
|
||||
|
||||
func TestNewErrorValidationVerificationFlowExpired(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
expiredAt := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
// "Now" is exactly two minutes after the flow expired.
|
||||
c := clock.NewMock(expiredAt.Add(2 * time.Minute))
|
||||
|
||||
msg := NewErrorValidationVerificationFlowExpired(c, expiredAt)
|
||||
|
||||
assert.Equal(t, ErrorValidationVerificationFlowExpired, msg.ID)
|
||||
assert.Equal(t, "The verification flow expired 2.00 minutes ago, please try again.", msg.Text)
|
||||
}
|
||||
|
||||
func TestVerificationCodeSentMessage(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tc := range []struct {
|
||||
via string
|
||||
wantID ID
|
||||
}{
|
||||
{via: "sms", wantID: InfoSelfServiceVerificationPhoneWithCodeSent},
|
||||
{via: "email", wantID: InfoSelfServiceVerificationEmailWithCodeSent},
|
||||
// Any unknown channel falls back to the email message.
|
||||
{via: "", wantID: InfoSelfServiceVerificationEmailWithCodeSent},
|
||||
} {
|
||||
t.Run("via="+tc.via, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, tc.wantID, VerificationCodeSentMessage(tc.via).ID)
|
||||
})
|
||||
}
|
||||
}
|
||||
14
text/type.go
Normal file
14
text/type.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package text
|
||||
|
||||
// swagger:enum UITextType
|
||||
type UITextType string
|
||||
|
||||
// aligned with https://github.com/ory/elements/blob/main/src/theme/message.css.ts
|
||||
const (
|
||||
Info UITextType = "info"
|
||||
Error UITextType = "error"
|
||||
Success UITextType = "success"
|
||||
)
|
||||
Reference in New Issue
Block a user