Skip to content

Commit dadc61a

Browse files
Release/v0.0.4 (#13)
Changelog: add authorizer fix api data
1 parent 6aaec05 commit dadc61a

35 files changed

Lines changed: 655 additions & 147 deletions

File tree

Taskfile.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ tasks:
311311
AWS_SECRET_ACCESS_KEY: '{{.ACCESS_KEY}}'
312312
# service specific envs
313313
TF_VAR_device_api_token: '{{.DEVICE_API_TOKEN}}'
314+
TF_VAR_jwt_secret: '{{.JWT_SECRET}}'
314315
silent: true
315316
internal: true
316317

@@ -436,6 +437,7 @@ tasks:
436437
KEY_ID: test
437438
ACCESS_KEY: test
438439
DEVICE_API_TOKEN: "000XXX000"
440+
JWT_SECRET: 'yHc8vF9xJzZP@!kU1&3aD#LmQw$rT^GnB5Xs2Ev*Ny%pC7o'
439441
silent: true
440442

441443
env/localstack/stop:
@@ -469,6 +471,10 @@ tasks:
469471
echo "Error: DEVICE_API_TOKEN is not set."
470472
exit 1
471473
fi
474+
if [ -z "$JWT_SECRET" ]; then
475+
echo "Error: JWT_SECRET is not set."
476+
exit 1
477+
fi
472478
- task: _terraform/fmt/check
473479
- task: _terraform/apply
474480
vars:
@@ -492,6 +498,7 @@ tasks:
492498
KEY_ID: '{{.AWS_ACCESS_KEY_ID}}'
493499
ACCESS_KEY: '{{.AWS_SECRET_ACCESS_KEY}}'
494500
DEVICE_API_TOKEN: '{{.DEVICE_API_TOKEN}}'
501+
JWT_SECRET: '{{.JWT_SECRET}}'
495502
- |
496503
echo "Updating all Lambda functions..."
497504
for dir in {{.git_root}}/cmd/*; do

cmd/api-dictionaries/.infra/readme.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,25 @@ Lambda for manage dictionaries.
66
## Define variables
77

88
```bash
9-
api="54ek0bxc7s"
9+
token="000XXX000"
10+
api="vp0yxvxfow"
1011
url="http://localhost:4566/restapis/${api}/prod/_user_request_/v1/dictionaries"
1112
```
1213

1314
```bash
1415
timestamp=$(date -u +%s)
1516
signature=$(echo -n "${timestamp}${arn_get}" | openssl dgst -sha256 -hmac "${token}" | sed 's/^.* //')
1617

17-
curl -X GET "${url}?is_public=true" -H "Content-Type: application/json" \
18-
-H "x-timestamp: ${timestamp}" \
19-
-H "x-signature: ${signature}"
18+
curl -X GET "${url}" -H "Content-Type: application/json" \
19+
-H "x-api-auth: ${timestamp}:::${signature}"
20+
21+
curl -X GET "${url}"
2022

23+
timestamp=$(date -u +%s)
24+
signature=$(echo -n "${timestamp}${arn_get}" | openssl dgst -sha256 -hmac "${token}" | sed 's/^.* //')
2125
curl -X POST ${url} \
2226
-d '{"description": "description", "filename": "1.csv", "name": "testdictionary", "author": "author", "category": "language", "subcategory": "ru-il", "public": true, "level": "A1", "topic":"topic"}' \
23-
-H "Content-Type: application/json"
27+
-H "Content-Type: application/json" \
28+
-H "x-timestamp: ${timestamp}" \
29+
-H "x-signature: ${signature}"
2430
```

cmd/api-dictionaries/handle_delete.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,18 @@ import (
99
"github.com/Mad-Pixels/applingo-api/openapi-interface"
1010
"github.com/Mad-Pixels/applingo-api/openapi-interface/gen/applingoapi"
1111
"github.com/Mad-Pixels/applingo-api/pkg/api"
12+
"github.com/Mad-Pixels/applingo-api/pkg/auth"
1213

1314
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
1415
"github.com/pkg/errors"
1516
"github.com/rs/zerolog"
1617
)
1718

1819
func handleDelete(ctx context.Context, _ zerolog.Logger, _ json.RawMessage, baseParams openapi.QueryParams) (any, *api.HandleError) {
20+
if api.MustGetMetaData(ctx).IsDevice() || !api.MustGetMetaData(ctx).HasPermissions(auth.User) {
21+
return nil, &api.HandleError{Status: http.StatusForbidden, Err: errors.New("insufficient permissions")}
22+
}
23+
1924
params := applingoapi.DeleteDictionariesV1Params{
2025
Name: baseParams.GetStringDefault("name", ""),
2126
Author: baseParams.GetStringDefault("author", ""),

cmd/api-dictionaries/handle_get.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/Mad-Pixels/applingo-api/openapi-interface"
1212
"github.com/Mad-Pixels/applingo-api/openapi-interface/gen/applingoapi"
1313
"github.com/Mad-Pixels/applingo-api/pkg/api"
14+
"github.com/Mad-Pixels/applingo-api/pkg/auth"
1415
"github.com/Mad-Pixels/applingo-api/pkg/cloud"
1516
"github.com/Mad-Pixels/applingo-api/pkg/serializer"
1617

@@ -24,6 +25,10 @@ import (
2425
const pageLimit = 60
2526

2627
func handleGet(ctx context.Context, logger zerolog.Logger, _ json.RawMessage, baseParams openapi.QueryParams) (any, *api.HandleError) {
28+
if !api.MustGetMetaData(ctx).HasPermissions(auth.Device) {
29+
return nil, &api.HandleError{Status: http.StatusForbidden, Err: errors.New("insufficient permissions")}
30+
}
31+
2732
validSortValues := map[applingoapi.BaseDictSortEnum]struct{}{
2833
applingoapi.Date: {},
2934
applingoapi.Rating: {},
@@ -58,7 +63,7 @@ func handleGet(ctx context.Context, logger zerolog.Logger, _ json.RawMessage, ba
5863

5964
var (
6065
wg sync.WaitGroup
61-
itemsCh = make(chan applingoapi.DictionaryItemV1, len(result.Items))
66+
itemsCh = make(chan applingodictionary.SchemaItem, len(result.Items))
6267
)
6368
response := applingoapi.DictionariesData{
6469
Items: make([]applingoapi.DictionaryItemV1, 0, len(result.Items)),
@@ -68,7 +73,7 @@ func handleGet(ctx context.Context, logger zerolog.Logger, _ json.RawMessage, ba
6873
go func(item map[string]types.AttributeValue) {
6974
defer wg.Done()
7075

71-
var dict applingoapi.DictionaryItemV1
76+
var dict applingodictionary.SchemaItem
7277
if err := attributevalue.UnmarshalMap(item, &dict); err != nil {
7378
logger.Warn().Err(err).Msg("Failed to unmarshal DynamoDB item")
7479
return
@@ -82,7 +87,17 @@ func handleGet(ctx context.Context, logger zerolog.Logger, _ json.RawMessage, ba
8287
}()
8388

8489
for item := range itemsCh {
85-
response.Items = append(response.Items, item)
90+
response.Items = append(response.Items, applingoapi.DictionaryItemV1{
91+
Category: applingoapi.BaseCategoryEnum(item.Category),
92+
Public: applingodictionary.IntToBool(item.IsPublic),
93+
Created: int64(item.Created),
94+
Description: item.Description,
95+
Dictionary: item.Dictionary,
96+
Author: item.Author,
97+
Name: item.Name,
98+
Level: item.Level,
99+
Topic: item.Topic,
100+
})
86101
}
87102
if result.LastEvaluatedKey != nil {
88103
var lastEvaluatedKeyMap map[string]interface{}

cmd/api-dictionaries/handle_post.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/Mad-Pixels/applingo-api/openapi-interface"
1515
"github.com/Mad-Pixels/applingo-api/openapi-interface/gen/applingoapi"
1616
"github.com/Mad-Pixels/applingo-api/pkg/api"
17+
"github.com/Mad-Pixels/applingo-api/pkg/auth"
1718
"github.com/Mad-Pixels/applingo-api/pkg/serializer"
1819

1920
"github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression"
@@ -22,6 +23,10 @@ import (
2223
)
2324

2425
func handlePost(ctx context.Context, logger zerolog.Logger, body json.RawMessage, _ openapi.QueryParams) (any, *api.HandleError) {
26+
if api.MustGetMetaData(ctx).IsDevice() || !api.MustGetMetaData(ctx).HasPermissions(auth.User) {
27+
return nil, &api.HandleError{Status: http.StatusForbidden, Err: errors.New("insufficient permissions")}
28+
}
29+
2530
var req applingoapi.RequestPostDictionariesV1
2631
if err := serializer.UnmarshalJSON(body, &req); err != nil {
2732
return nil, &api.HandleError{Status: http.StatusBadRequest, Err: err}

cmd/api-levels/handle_get.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ package main
33
import (
44
"context"
55
"encoding/json"
6+
"errors"
67
"net/http"
78

89
"github.com/Mad-Pixels/applingo-api/dynamodb-interface/gen/applingolevel"
910
"github.com/Mad-Pixels/applingo-api/openapi-interface"
1011
"github.com/Mad-Pixels/applingo-api/openapi-interface/gen/applingoapi"
1112
"github.com/Mad-Pixels/applingo-api/pkg/api"
13+
"github.com/Mad-Pixels/applingo-api/pkg/auth"
1214

1315
"github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
1416
"github.com/rs/zerolog"
@@ -17,16 +19,28 @@ import (
1719
const pageLimit = 6
1820

1921
func handleGet(ctx context.Context, logger zerolog.Logger, _ json.RawMessage, _ openapi.QueryParams) (any, *api.HandleError) {
22+
if !api.MustGetMetaData(ctx).HasPermissions(auth.Device) {
23+
return nil, &api.HandleError{Status: http.StatusForbidden, Err: errors.New("insufficient permissions")}
24+
}
25+
2026
scanInput := dbDynamo.BuildScanInput(applingolevel.TableName, pageLimit, nil)
2127
result, err := dbDynamo.Scan(ctx, applingolevel.TableName, scanInput)
2228
if err != nil {
2329
return nil, &api.HandleError{Status: http.StatusInternalServerError, Err: err}
2430
}
2531

26-
var items []applingoapi.LevelItemV1
27-
if err := attributevalue.UnmarshalListOfMaps(result.Items, &items); err != nil {
32+
var dynamoItems []applingolevel.SchemaItem
33+
if err := attributevalue.UnmarshalListOfMaps(result.Items, &dynamoItems); err != nil {
2834
return nil, &api.HandleError{Status: http.StatusInternalServerError, Err: err}
2935
}
36+
37+
var items []applingoapi.LevelItemV1
38+
for _, item := range dynamoItems {
39+
items = append(items, applingoapi.LevelItemV1{
40+
Code: item.Code,
41+
Level: item.Level,
42+
})
43+
}
3044
return openapi.DataResponseLevels(applingoapi.LevelsData{
3145
Items: items,
3246
}), nil

cmd/api-reports/handle_post.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ import (
1818
)
1919

2020
func handlePost(ctx context.Context, _ zerolog.Logger, raw json.RawMessage, _ openapi.QueryParams) (any, *api.HandleError) {
21+
if !api.MustGetMetaData(ctx).IsDevice() {
22+
return nil, &api.HandleError{Status: http.StatusForbidden, Err: errors.New("insufficient permissions")}
23+
}
24+
2125
var req applingoapi.RequestPostReportsV1
2226
if err := serializer.UnmarshalJSON(raw, &req); err != nil {
2327
return nil, &api.HandleError{Status: http.StatusBadRequest, Err: err}

cmd/api-subcategories/.infra/readme.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@ url="http://localhost:4566/restapis/${api}/prod/_user_request_/v1/subcategories"
1414
```bash
1515
timestamp=$(date -u +%s)
1616
signature=$(echo -n "${timestamp}" | openssl dgst -sha256 -hmac "${token}" | sed 's/^.* //')
17-
curl -X POST ${url}/${device_path_query} \
17+
curl -X GET ${url} \
1818
-d "${body}" \
1919
-H "Content-Type: application/json" \
20-
-H "x-timestamp: ${timestamp}" \
21-
-H "x-signature: ${signature}"
20+
-H "x-api-auth: ${timestamp}:::${signature}"
2221
```
2322

2423
## v1/category/query

cmd/api-subcategories/handle_delete.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,18 @@ import (
99
"github.com/Mad-Pixels/applingo-api/openapi-interface"
1010
"github.com/Mad-Pixels/applingo-api/openapi-interface/gen/applingoapi"
1111
"github.com/Mad-Pixels/applingo-api/pkg/api"
12+
"github.com/Mad-Pixels/applingo-api/pkg/auth"
1213

1314
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
1415
"github.com/pkg/errors"
1516
"github.com/rs/zerolog"
1617
)
1718

1819
func handleDelete(ctx context.Context, logger zerolog.Logger, _ json.RawMessage, baseParams openapi.QueryParams) (any, *api.HandleError) {
20+
if api.MustGetMetaData(ctx).IsDevice() || !api.MustGetMetaData(ctx).HasPermissions(auth.User) {
21+
return nil, &api.HandleError{Status: http.StatusForbidden, Err: errors.New("insufficient permissions")}
22+
}
23+
1924
validSideValues := map[applingoapi.BaseSideEnum]struct{}{
2025
applingoapi.Front: {},
2126
applingoapi.Back: {},

cmd/api-subcategories/handle_get.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/Mad-Pixels/applingo-api/openapi-interface"
1111
"github.com/Mad-Pixels/applingo-api/openapi-interface/gen/applingoapi"
1212
"github.com/Mad-Pixels/applingo-api/pkg/api"
13+
"github.com/Mad-Pixels/applingo-api/pkg/auth"
1314
"github.com/Mad-Pixels/applingo-api/pkg/cloud"
1415

1516
"github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
@@ -21,6 +22,10 @@ import (
2122
const pageLimit = 1000
2223

2324
func handleGet(ctx context.Context, logger zerolog.Logger, _ json.RawMessage, baseParams openapi.QueryParams) (any, *api.HandleError) {
25+
if !api.MustGetMetaData(ctx).HasPermissions(auth.Device) {
26+
return nil, &api.HandleError{Status: http.StatusForbidden, Err: errors.New("insufficient permissions")}
27+
}
28+
2429
validSideValues := map[applingoapi.BaseSideEnum]struct{}{
2530
applingoapi.Front: {},
2631
applingoapi.Back: {},
@@ -62,17 +67,16 @@ func handleGet(ctx context.Context, logger zerolog.Logger, _ json.RawMessage, ba
6267
}
6368

6469
var (
65-
wg sync.WaitGroup
66-
itemsCh = make(chan applingoapi.SubcategoryItemV1, len(items))
70+
wg sync.WaitGroup
71+
itemsCh = make(chan applingosubcategory.SchemaItem, len(items))
72+
response = applingoapi.CategoriesData{}
6773
)
68-
response := applingoapi.CategoriesData{}
69-
7074
for _, item := range items {
7175
wg.Add(1)
7276
go func(item map[string]types.AttributeValue) {
7377
defer wg.Done()
7478

75-
var category applingoapi.SubcategoryItemV1
79+
var category applingosubcategory.SchemaItem
7680
if err := attributevalue.UnmarshalMap(item, &category); err != nil {
7781
logger.Warn().Err(err).Msg("Failed to unmarshal DynamoDB item")
7882
return
@@ -86,7 +90,7 @@ func handleGet(ctx context.Context, logger zerolog.Logger, _ json.RawMessage, ba
8690
}()
8791

8892
for item := range itemsCh {
89-
switch item.Side {
93+
switch applingoapi.BaseSideEnum(item.Side) {
9094
case applingoapi.Front:
9195
response.FrontSide = append(response.FrontSide, applingoapi.SubcategoryItemV1{
9296
Code: item.Code,

0 commit comments

Comments
 (0)