mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-02-04 12:46:45 +00:00
fix: remove ambiguous characters from login code
This commit is contained in:
@@ -876,7 +876,7 @@ func NewOneTimeAccessToken(userID string, ttl time.Duration, withDeviceToken boo
|
|||||||
tokenLength = 6
|
tokenLength = 6
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := utils.GenerateRandomAlphanumericString(tokenLength)
|
token, err := utils.GenerateRandomUnambiguousString(tokenLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,17 @@ import (
|
|||||||
// GenerateRandomAlphanumericString generates a random alphanumeric string of the given length
|
// GenerateRandomAlphanumericString generates a random alphanumeric string of the given length
|
||||||
func GenerateRandomAlphanumericString(length int) (string, error) {
|
func GenerateRandomAlphanumericString(length int) (string, error) {
|
||||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||||
|
return GenerateRandomString(length, charset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateRandomUnambiguousString generates a random string of the given length using unambiguous characters
|
||||||
|
func GenerateRandomUnambiguousString(length int) (string, error) {
|
||||||
|
const charset = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789"
|
||||||
|
return GenerateRandomString(length, charset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateRandomString generates a random string of the given length using the provided character set
|
||||||
|
func GenerateRandomString(length int, charset string) (string, error) {
|
||||||
|
|
||||||
if length <= 0 {
|
if length <= 0 {
|
||||||
return "", errors.New("length must be a positive integer")
|
return "", errors.New("length must be a positive integer")
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -49,6 +50,77 @@ func TestGenerateRandomAlphanumericString(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenerateRandomUnambiguousString(t *testing.T) {
|
||||||
|
t.Run("valid length returns correct string", func(t *testing.T) {
|
||||||
|
const length = 10
|
||||||
|
str, err := GenerateRandomUnambiguousString(length)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
if len(str) != length {
|
||||||
|
t.Errorf("Expected length %d, got %d", length, len(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
matched, err := regexp.MatchString(`^[abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789]+$`, str)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Regex match failed: %v", err)
|
||||||
|
}
|
||||||
|
if !matched {
|
||||||
|
t.Errorf("String contains ambiguous characters: %s", str)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("zero length returns error", func(t *testing.T) {
|
||||||
|
_, err := GenerateRandomUnambiguousString(0)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error for zero length, got nil")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("negative length returns error", func(t *testing.T) {
|
||||||
|
_, err := GenerateRandomUnambiguousString(-1)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error for negative length, got nil")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateRandomString(t *testing.T) {
|
||||||
|
t.Run("valid length returns characters from charset", func(t *testing.T) {
|
||||||
|
const length = 20
|
||||||
|
const charset = "abc"
|
||||||
|
str, err := GenerateRandomString(length, charset)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
if len(str) != length {
|
||||||
|
t.Errorf("Expected length %d, got %d", length, len(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range str {
|
||||||
|
if !strings.ContainsRune(charset, r) {
|
||||||
|
t.Fatalf("String contains character outside charset: %q", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("zero length returns error", func(t *testing.T) {
|
||||||
|
_, err := GenerateRandomString(0, "abc")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error for zero length, got nil")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("negative length returns error", func(t *testing.T) {
|
||||||
|
_, err := GenerateRandomString(-1, "abc")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error for negative length, got nil")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestCapitalizeFirstLetter(t *testing.T) {
|
func TestCapitalizeFirstLetter(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
@@ -140,7 +140,6 @@
|
|||||||
|
|
||||||
/* Font */
|
/* Font */
|
||||||
--font-playfair: 'Playfair Display', serif;
|
--font-playfair: 'Playfair Display', serif;
|
||||||
--font-code: 'Google Sans', sans-serif;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
@@ -176,11 +175,6 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
src: url('/fonts/PlayfairDisplay-Bold.woff') format('woff');
|
src: url('/fonts/PlayfairDisplay-Bold.woff') format('woff');
|
||||||
}
|
}
|
||||||
@font-face {
|
|
||||||
font-family: 'Google Sans';
|
|
||||||
font-weight: 600;
|
|
||||||
src: url('/fonts/GoogleSansCode-SemiBold.ttf') format('truetype');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes accordion-down {
|
@keyframes accordion-down {
|
||||||
|
|||||||
@@ -112,7 +112,7 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<div class="flex flex-col items-center gap-2">
|
<div class="flex flex-col items-center gap-2">
|
||||||
<CopyToClipboard value={code!}>
|
<CopyToClipboard value={code!}>
|
||||||
<p class="text-3xl font-code">{code}</p>
|
<p class="text-3xl font-bold">{code}</p>
|
||||||
</CopyToClipboard>
|
</CopyToClipboard>
|
||||||
|
|
||||||
<div class="flex items-center justify-center gap-3 my-2 text-muted-foreground">
|
<div class="flex items-center justify-center gap-3 my-2 text-muted-foreground">
|
||||||
@@ -124,12 +124,12 @@
|
|||||||
<Qrcode
|
<Qrcode
|
||||||
class="mb-2"
|
class="mb-2"
|
||||||
value={oneTimeLink}
|
value={oneTimeLink}
|
||||||
size={180}
|
size={150}
|
||||||
color={mode.current === 'dark' ? '#FFFFFF' : '#000000'}
|
color={mode.current === 'dark' ? '#FFFFFF' : '#000000'}
|
||||||
backgroundColor={mode.current === 'dark' ? '#000000' : '#FFFFFF'}
|
backgroundColor={mode.current === 'dark' ? '#000000' : '#FFFFFF'}
|
||||||
/>
|
/>
|
||||||
<CopyToClipboard value={oneTimeLink!}>
|
<CopyToClipboard value={oneTimeLink!}>
|
||||||
<p data-testId="login-code-link">{oneTimeLink!}</p>
|
<p data-testId="login-code-link" class="text-sm">{oneTimeLink!}</p>
|
||||||
</CopyToClipboard>
|
</CopyToClipboard>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
|
|
||||||
<div class="flex flex-col items-center gap-2">
|
<div class="flex flex-col items-center gap-2">
|
||||||
<CopyToClipboard value={code!}>
|
<CopyToClipboard value={code!}>
|
||||||
<p class="text-3xl font-code">{code}</p>
|
<p class="text-3xl font-bold">{code}</p>
|
||||||
</CopyToClipboard>
|
</CopyToClipboard>
|
||||||
<div class="flex items-center justify-center gap-3 my-2 text-muted-foreground">
|
<div class="flex items-center justify-center gap-3 my-2 text-muted-foreground">
|
||||||
<Separator />
|
<Separator />
|
||||||
@@ -62,12 +62,12 @@
|
|||||||
<Qrcode
|
<Qrcode
|
||||||
class="mb-2"
|
class="mb-2"
|
||||||
value={loginCodeLink}
|
value={loginCodeLink}
|
||||||
size={180}
|
size={150}
|
||||||
color={mode.current === 'dark' ? '#FFFFFF' : '#000000'}
|
color={mode.current === 'dark' ? '#FFFFFF' : '#000000'}
|
||||||
backgroundColor={mode.current === 'dark' ? '#000000' : '#FFFFFF'}
|
backgroundColor={mode.current === 'dark' ? '#000000' : '#FFFFFF'}
|
||||||
/>
|
/>
|
||||||
<CopyToClipboard value={loginCodeLink!}>
|
<CopyToClipboard value={loginCodeLink!}>
|
||||||
<p data-testId="login-code-link">{loginCodeLink!}</p>
|
<p class="text-sm" data-testId="login-code-link">{loginCodeLink!}</p>
|
||||||
</CopyToClipboard>
|
</CopyToClipboard>
|
||||||
</div>
|
</div>
|
||||||
</Dialog.Content>
|
</Dialog.Content>
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user