feat: support time_zone for user registration context
This commit is contained in:
@@ -17,6 +17,7 @@ import (
|
||||
)
|
||||
|
||||
const blockFlowPublicKey = "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8="
|
||||
const blockFlowTimeZone = "Europe/Kaliningrad"
|
||||
|
||||
func TestBlockUserAffectsLaterSendAndConfirmFlows(t *testing.T) {
|
||||
t.Parallel()
|
||||
@@ -81,6 +82,7 @@ func TestBlockUserAffectsLaterSendAndConfirmFlows(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: blockFlowPublicKey,
|
||||
TimeZone: blockFlowTimeZone,
|
||||
})
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, shared.ErrorCodeBlockedByPolicy, shared.CodeOf(err))
|
||||
|
||||
@@ -28,6 +28,7 @@ func TestExecuteReturnsInvalidCodeForThrottledChallengeWithoutConsumingAttempts(
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, shared.ErrorCodeInvalidCode, shared.CodeOf(err))
|
||||
|
||||
@@ -31,6 +31,7 @@ func TestExecuteConfirmsChallengeAfterTransientProjectionPublishFailures(t *test
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "device-session-1", result.DeviceSessionID)
|
||||
@@ -57,6 +58,7 @@ func TestExecuteConfirmedRetryRepublishesAfterTransientProjectionPublishFailures
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "device-session-1", result.DeviceSessionID)
|
||||
@@ -79,6 +81,7 @@ func TestExecuteRepairsProjectionOnIdenticalRetryAfterExhaustedPublishRetries(t
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, shared.ErrorCodeServiceUnavailable, shared.CodeOf(err))
|
||||
@@ -99,6 +102,7 @@ func TestExecuteRepairsProjectionOnIdenticalRetryAfterExhaustedPublishRetries(t
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "device-session-1", result.DeviceSessionID)
|
||||
|
||||
@@ -19,9 +19,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
revokeReasonConfirmRace common.RevokeReasonCode = "confirm_race_repair"
|
||||
revokeActorTypeService common.RevokeActorType = "service"
|
||||
revokeActorIDService = "confirmemailcode"
|
||||
revokeReasonConfirmRace common.RevokeReasonCode = "confirm_race_repair"
|
||||
revokeActorTypeService common.RevokeActorType = "service"
|
||||
revokeActorIDService = "confirmemailcode"
|
||||
defaultPreferredLanguage = "en"
|
||||
)
|
||||
|
||||
// Input describes one public confirm-email-code request.
|
||||
@@ -35,6 +36,11 @@ type Input struct {
|
||||
// ClientPublicKey is the base64-encoded raw 32-byte Ed25519 public key that
|
||||
// should be registered for the created device session.
|
||||
ClientPublicKey string
|
||||
|
||||
// TimeZone is the client-selected IANA time zone name that should be
|
||||
// forwarded as create-only registration context when the user does not yet
|
||||
// exist.
|
||||
TimeZone string
|
||||
}
|
||||
|
||||
// Result describes one public confirm-email-code response.
|
||||
@@ -192,6 +198,10 @@ func (s *Service) Execute(ctx context.Context, input Input) (result Result, err
|
||||
if err != nil {
|
||||
return Result{}, err
|
||||
}
|
||||
timeZone, err := shared.ParseTimeZone(input.TimeZone)
|
||||
if err != nil {
|
||||
return Result{}, err
|
||||
}
|
||||
|
||||
for attempt := 0; attempt < shared.MaxCompareAndSwapRetries; attempt++ {
|
||||
current, err := s.challengeStore.Get(ctx, challengeID)
|
||||
@@ -236,7 +246,13 @@ func (s *Service) Execute(ctx context.Context, input Input) (result Result, err
|
||||
return Result{}, shared.InvalidCode()
|
||||
}
|
||||
|
||||
ensureUserResult, err := s.userDirectory.EnsureUserByEmail(ctx, current.Email)
|
||||
ensureUserResult, err := s.userDirectory.EnsureUserByEmail(ctx, ports.EnsureUserInput{
|
||||
Email: current.Email,
|
||||
RegistrationContext: &ports.RegistrationContext{
|
||||
PreferredLanguage: defaultPreferredLanguage,
|
||||
TimeZone: timeZone,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return Result{}, shared.ServiceUnavailable(err)
|
||||
}
|
||||
|
||||
@@ -11,10 +11,13 @@ import (
|
||||
"galaxy/authsession/internal/domain/common"
|
||||
"galaxy/authsession/internal/domain/devicesession"
|
||||
"galaxy/authsession/internal/domain/userresolution"
|
||||
"galaxy/authsession/internal/ports"
|
||||
"galaxy/authsession/internal/service/shared"
|
||||
"galaxy/authsession/internal/testkit"
|
||||
)
|
||||
|
||||
const confirmEmailCodeTimeZone = "Europe/Kaliningrad"
|
||||
|
||||
func TestExecuteConfirmsChallengeForExistingUser(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -31,6 +34,7 @@ func TestExecuteConfirmsChallengeForExistingUser(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if err != nil {
|
||||
require.Failf(t, "test failed", "Execute() returned error: %v", err)
|
||||
@@ -75,6 +79,7 @@ func TestExecuteConfirmsChallengeByCreatingUser(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if err != nil {
|
||||
require.Failf(t, "test failed", "Execute() returned error: %v", err)
|
||||
@@ -114,6 +119,7 @@ func TestExecuteConfirmsSuppressedChallenge(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if err != nil {
|
||||
require.Failf(t, "test failed", "Execute() returned error: %v", err)
|
||||
@@ -132,6 +138,7 @@ func TestExecuteReturnsChallengeNotFound(t *testing.T) {
|
||||
ChallengeID: "missing",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if shared.CodeOf(err) != shared.ErrorCodeChallengeNotFound {
|
||||
require.Failf(t, "test failed", "Execute() error code = %q, want %q", shared.CodeOf(err), shared.ErrorCodeChallengeNotFound)
|
||||
@@ -152,6 +159,7 @@ func TestExecuteReturnsChallengeExpiredAndMarksExpired(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if shared.CodeOf(err) != shared.ErrorCodeChallengeExpired {
|
||||
require.Failf(t, "test failed", "Execute() error code = %q, want %q", shared.CodeOf(err), shared.ErrorCodeChallengeExpired)
|
||||
@@ -194,6 +202,7 @@ func TestExecuteReturnsChallengeExpiredForConfirmedChallengeAfterRetentionWindow
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if shared.CodeOf(err) != shared.ErrorCodeChallengeExpired {
|
||||
require.Failf(t, "test failed", "Execute() error code = %q, want %q", shared.CodeOf(err), shared.ErrorCodeChallengeExpired)
|
||||
@@ -220,12 +229,32 @@ func TestExecuteReturnsInvalidClientPublicKey(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: "invalid",
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if shared.CodeOf(err) != shared.ErrorCodeInvalidClientPublicKey {
|
||||
require.Failf(t, "test failed", "Execute() error code = %q, want %q", shared.CodeOf(err), shared.ErrorCodeInvalidClientPublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteReturnsInvalidRequestForInvalidTimeZone(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
service := mustNewConfirmService(t, newConfirmDeps(t))
|
||||
|
||||
_, err := service.Execute(context.Background(), Input{
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: "Mars/Olympus",
|
||||
})
|
||||
if shared.CodeOf(err) != shared.ErrorCodeInvalidRequest {
|
||||
require.Failf(t, "test failed", "Execute() error code = %q, want %q", shared.CodeOf(err), shared.ErrorCodeInvalidRequest)
|
||||
}
|
||||
if err == nil || err.Error() != "time_zone must be a valid IANA time zone name" {
|
||||
require.Failf(t, "test failed", "Execute() error = %v, want invalid time_zone detail", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteInvalidCodeIncrementsAttempts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -239,6 +268,7 @@ func TestExecuteInvalidCodeIncrementsAttempts(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "000000",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if shared.CodeOf(err) != shared.ErrorCodeInvalidCode {
|
||||
require.Failf(t, "test failed", "Execute() error code = %q, want %q", shared.CodeOf(err), shared.ErrorCodeInvalidCode)
|
||||
@@ -268,6 +298,7 @@ func TestExecuteFifthInvalidAttemptMarksChallengeFailed(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "000000",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if shared.CodeOf(err) != shared.ErrorCodeInvalidCode {
|
||||
require.Failf(t, "test failed", "Execute() error code = %q, want %q", shared.CodeOf(err), shared.ErrorCodeInvalidCode)
|
||||
@@ -304,6 +335,7 @@ func TestExecuteDoesNotCreateSessionAfterTooManyAttempts(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if shared.CodeOf(err) != shared.ErrorCodeInvalidCode {
|
||||
require.Failf(t, "test failed", "Execute() error code = %q, want %q", shared.CodeOf(err), shared.ErrorCodeInvalidCode)
|
||||
@@ -337,6 +369,7 @@ func TestExecuteReturnsSameSessionIDForIdempotentRetryAndRepublishes(t *testing.
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if err != nil {
|
||||
require.Failf(t, "test failed", "Execute() returned error: %v", err)
|
||||
@@ -370,6 +403,7 @@ func TestExecuteReturnsInvalidCodeForDifferentKeyDuringIdempotentRetry(t *testin
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: alternatePublicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if shared.CodeOf(err) != shared.ErrorCodeInvalidCode {
|
||||
require.Failf(t, "test failed", "Execute() error code = %q, want %q", shared.CodeOf(err), shared.ErrorCodeInvalidCode)
|
||||
@@ -425,6 +459,7 @@ func TestExecuteReturnsInvalidCodeForNonConfirmableStates(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if shared.CodeOf(err) != shared.ErrorCodeInvalidCode {
|
||||
require.Failf(t, "test failed", "Execute() error code = %q, want %q", shared.CodeOf(err), shared.ErrorCodeInvalidCode)
|
||||
@@ -457,6 +492,7 @@ func TestExecuteMarksChallengeFailedAndReturnsBlockedByPolicy(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if shared.CodeOf(err) != shared.ErrorCodeBlockedByPolicy {
|
||||
require.Failf(t, "test failed", "Execute() error code = %q, want %q", shared.CodeOf(err), shared.ErrorCodeBlockedByPolicy)
|
||||
@@ -492,6 +528,7 @@ func TestExecuteReturnsSessionLimitExceededWithoutConsumingChallenge(t *testing.
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if shared.CodeOf(err) != shared.ErrorCodeSessionLimitExceeded {
|
||||
require.Failf(t, "test failed", "Execute() error code = %q, want %q", shared.CodeOf(err), shared.ErrorCodeSessionLimitExceeded)
|
||||
@@ -509,6 +546,57 @@ func TestExecuteReturnsSessionLimitExceededWithoutConsumingChallenge(t *testing.
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecutePassesRegistrationContextToUserDirectory(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
deps := newConfirmDeps(t)
|
||||
recordingDirectory := &recordingEnsureUserDirectory{delegate: deps.userDirectory}
|
||||
deps.userDirectory = nil
|
||||
|
||||
if err := recordingDirectory.delegate.QueueCreatedUserIDs(common.UserID("user-created")); err != nil {
|
||||
require.Failf(t, "test failed", "QueueCreatedUserIDs() returned error: %v", err)
|
||||
}
|
||||
if err := deps.challengeStore.Create(context.Background(), sentChallengeFixture(t, deps.hasher, "challenge-1", "new@example.com", "654321", deps.now.Add(-time.Minute), deps.now.Add(time.Minute))); err != nil {
|
||||
require.Failf(t, "test failed", "Create() returned error: %v", err)
|
||||
}
|
||||
|
||||
service, err := New(
|
||||
deps.challengeStore,
|
||||
deps.sessionStore,
|
||||
recordingDirectory,
|
||||
deps.configProvider,
|
||||
deps.publisher,
|
||||
deps.idGenerator,
|
||||
deps.hasher,
|
||||
testkit.FixedClock{Time: deps.now},
|
||||
)
|
||||
if err != nil {
|
||||
require.Failf(t, "test failed", "New() returned error: %v", err)
|
||||
}
|
||||
|
||||
_, err = service.Execute(context.Background(), Input{
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if err != nil {
|
||||
require.Failf(t, "test failed", "Execute() returned error: %v", err)
|
||||
}
|
||||
if recordingDirectory.lastEnsureInput.Email != common.Email("new@example.com") {
|
||||
require.Failf(t, "test failed", "last ensure email = %q, want %q", recordingDirectory.lastEnsureInput.Email, common.Email("new@example.com"))
|
||||
}
|
||||
if recordingDirectory.lastEnsureInput.RegistrationContext == nil {
|
||||
require.FailNow(t, "last ensure registration context = nil, want value")
|
||||
}
|
||||
if recordingDirectory.lastEnsureInput.RegistrationContext.PreferredLanguage != "en" {
|
||||
require.Failf(t, "test failed", "preferred language = %q, want %q", recordingDirectory.lastEnsureInput.RegistrationContext.PreferredLanguage, "en")
|
||||
}
|
||||
if recordingDirectory.lastEnsureInput.RegistrationContext.TimeZone != confirmEmailCodeTimeZone {
|
||||
require.Failf(t, "test failed", "time zone = %q, want %q", recordingDirectory.lastEnsureInput.RegistrationContext.TimeZone, confirmEmailCodeTimeZone)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteReturnsServiceUnavailableThenSucceedsIdempotentlyAfterPublishFailure(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -526,6 +614,7 @@ func TestExecuteReturnsServiceUnavailableThenSucceedsIdempotentlyAfterPublishFai
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if shared.CodeOf(err) != shared.ErrorCodeServiceUnavailable {
|
||||
require.Failf(t, "test failed", "first Execute() error code = %q, want %q", shared.CodeOf(err), shared.ErrorCodeServiceUnavailable)
|
||||
@@ -536,6 +625,7 @@ func TestExecuteReturnsServiceUnavailableThenSucceedsIdempotentlyAfterPublishFai
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
if err != nil {
|
||||
require.Failf(t, "test failed", "second Execute() returned error: %v", err)
|
||||
@@ -680,3 +770,33 @@ func publicKeyString() string {
|
||||
func alternatePublicKeyString() string {
|
||||
return "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE="
|
||||
}
|
||||
|
||||
// recordingEnsureUserDirectory records the last ensure input while delegating
|
||||
// behavior to the in-memory testkit directory.
|
||||
type recordingEnsureUserDirectory struct {
|
||||
delegate *testkit.InMemoryUserDirectory
|
||||
lastEnsureInput ports.EnsureUserInput
|
||||
}
|
||||
|
||||
func (d *recordingEnsureUserDirectory) ResolveByEmail(ctx context.Context, email common.Email) (userresolution.Result, error) {
|
||||
return d.delegate.ResolveByEmail(ctx, email)
|
||||
}
|
||||
|
||||
func (d *recordingEnsureUserDirectory) ExistsByUserID(ctx context.Context, userID common.UserID) (bool, error) {
|
||||
return d.delegate.ExistsByUserID(ctx, userID)
|
||||
}
|
||||
|
||||
func (d *recordingEnsureUserDirectory) EnsureUserByEmail(ctx context.Context, input ports.EnsureUserInput) (ports.EnsureUserResult, error) {
|
||||
d.lastEnsureInput = input
|
||||
return d.delegate.EnsureUserByEmail(ctx, input)
|
||||
}
|
||||
|
||||
func (d *recordingEnsureUserDirectory) BlockByUserID(ctx context.Context, input ports.BlockUserByIDInput) (ports.BlockUserResult, error) {
|
||||
return d.delegate.BlockByUserID(ctx, input)
|
||||
}
|
||||
|
||||
func (d *recordingEnsureUserDirectory) BlockByEmail(ctx context.Context, input ports.BlockUserByEmailInput) (ports.BlockUserResult, error) {
|
||||
return d.delegate.BlockByEmail(ctx, input)
|
||||
}
|
||||
|
||||
var _ ports.UserDirectory = (*recordingEnsureUserDirectory)(nil)
|
||||
|
||||
@@ -51,6 +51,7 @@ func TestExecuteWithRuntimeStubUserDirectory(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "device-session-1", result.DeviceSessionID)
|
||||
@@ -92,6 +93,7 @@ func TestExecuteWithRuntimeStubUserDirectory(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, shared.ErrorCodeBlockedByPolicy, shared.CodeOf(err))
|
||||
|
||||
@@ -44,6 +44,7 @@ func TestExecuteRecordsInvalidCodeMetricForThrottledChallenge(t *testing.T) {
|
||||
ChallengeID: "challenge-1",
|
||||
Code: "654321",
|
||||
ClientPublicKey: publicKeyString(),
|
||||
TimeZone: confirmEmailCodeTimeZone,
|
||||
})
|
||||
require.Error(t, err)
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ func (d *countingUserDirectory) ExistsByUserID(context.Context, common.UserID) (
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (d *countingUserDirectory) EnsureUserByEmail(context.Context, common.Email) (ports.EnsureUserResult, error) {
|
||||
func (d *countingUserDirectory) EnsureUserByEmail(context.Context, ports.EnsureUserInput) (ports.EnsureUserResult, error) {
|
||||
return ports.EnsureUserResult{}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,20 @@ func ParseClientPublicKey(value string) (common.ClientPublicKey, error) {
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// ParseTimeZone trims value and validates it as an IANA time zone name.
|
||||
func ParseTimeZone(value string) (string, error) {
|
||||
timeZone := NormalizeString(value)
|
||||
if timeZone == "" {
|
||||
return "", InvalidRequest("time_zone must not be empty")
|
||||
}
|
||||
|
||||
if _, err := time.LoadLocation(timeZone); err != nil {
|
||||
return "", InvalidRequest("time_zone must be a valid IANA time zone name")
|
||||
}
|
||||
|
||||
return timeZone, nil
|
||||
}
|
||||
|
||||
// ParseRevokeReasonCode trims value and validates it as one machine-readable
|
||||
// revoke reason code.
|
||||
func ParseRevokeReasonCode(value string) (common.RevokeReasonCode, error) {
|
||||
|
||||
@@ -34,6 +34,19 @@ func TestParseClientPublicKey(t *testing.T) {
|
||||
assert.Equal(t, ErrorCodeInvalidClientPublicKey, CodeOf(err))
|
||||
}
|
||||
|
||||
func TestParseTimeZone(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
timeZone, err := ParseTimeZone(" Europe/Kaliningrad ")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Europe/Kaliningrad", timeZone)
|
||||
|
||||
_, err = ParseTimeZone("Mars/Olympus")
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, ErrorCodeInvalidRequest, CodeOf(err))
|
||||
assert.Equal(t, "time_zone must be a valid IANA time zone name", err.Error())
|
||||
}
|
||||
|
||||
func TestToSession(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user