Skip to content

Commit b2902d1

Browse files
authored
Merge pull request #106 from silinternational/feature/scan-api-key
add the ability to scan the WebAuthn table by apiKey
2 parents 157f6e1 + 270165a commit b2902d1

File tree

2 files changed

+65
-2
lines changed

2 files changed

+65
-2
lines changed

storage.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313

1414
const StorageContextKey = "storage"
1515

16+
var tableNameMissingError = errors.New("table name must not be empty")
17+
1618
// Storage provides wrapper methods for interacting with DynamoDB
1719
type Storage struct {
1820
client *dynamodb.Client
@@ -51,7 +53,7 @@ func (s *Storage) Store(table string, item interface{}) error {
5153
// Load retrieves the value at key and unmarshals it into item.
5254
func (s *Storage) Load(table, attrName, attrVal string, item interface{}) error {
5355
if table == "" {
54-
return errors.New("table must not be empty")
56+
return tableNameMissingError
5557
}
5658
if attrName == "" {
5759
return errors.New("attrName must not be empty")
@@ -84,7 +86,7 @@ func (s *Storage) Load(table, attrName, attrVal string, item interface{}) error
8486
// Delete deletes key.
8587
func (s *Storage) Delete(table, attrName, attrVal string) error {
8688
if table == "" {
87-
return errors.New("table must not be empty")
89+
return tableNameMissingError
8890
}
8991
if attrName == "" {
9092
return errors.New("attrName must not be empty")
@@ -101,3 +103,34 @@ func (s *Storage) Delete(table, attrName, attrVal string) error {
101103
_, err := s.client.DeleteItem(ctx, input)
102104
return err
103105
}
106+
107+
// ScanApiKey a table using apiKey-index
108+
func (s *Storage) ScanApiKey(table, apiKey string, items any) error {
109+
if table == "" {
110+
return tableNameMissingError
111+
}
112+
113+
input := &dynamodb.ScanInput{
114+
FilterExpression: aws.String("apiKey = :val"),
115+
ExpressionAttributeValues: map[string]types.AttributeValue{
116+
":val": &types.AttributeValueMemberS{Value: apiKey},
117+
},
118+
TableName: aws.String(table),
119+
}
120+
121+
ctx := context.Background()
122+
result, err := s.client.Scan(ctx, input)
123+
if err != nil {
124+
return err
125+
}
126+
127+
if result.LastEvaluatedKey != nil {
128+
return errors.New("too many results, pagination has not been implemented")
129+
}
130+
131+
err = attributevalue.UnmarshalListOfMaps(result.Items, &items)
132+
if err != nil {
133+
return err
134+
}
135+
return nil
136+
}

storage_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,33 @@ func (ms *MfaSuite) TestStorage_StoreLoad() {
7171
})
7272
}
7373
}
74+
75+
func (ms *MfaSuite) TestStorageScanApiKey() {
76+
cfg, err := config.LoadDefaultConfig(
77+
context.Background(),
78+
config.WithRegion("local"),
79+
config.WithBaseEndpoint(os.Getenv("AWS_ENDPOINT")),
80+
)
81+
ms.NoError(err)
82+
83+
s, err := NewStorage(cfg)
84+
ms.NoError(err)
85+
must(s.Store(TestTableName, &WebauthnUser{
86+
ID: "user1",
87+
ApiKeyValue: "key1",
88+
EncryptedAppId: "xyz123",
89+
}))
90+
must(s.Store(TestTableName, &WebauthnUser{
91+
ID: "user2",
92+
ApiKeyValue: "key2",
93+
EncryptedAppId: "abc123",
94+
}))
95+
96+
var users []WebauthnUser
97+
err = s.ScanApiKey(TestTableName, "key1", &users)
98+
ms.NoError(err)
99+
ms.Len(users, 1)
100+
ms.Equal("user1", users[0].ID)
101+
ms.Equal("key1", users[0].ApiKeyValue)
102+
ms.Equal("xyz123", users[0].EncryptedAppId)
103+
}

0 commit comments

Comments
 (0)