Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VEGA-2260 Record updates in changes table #minor #98

Merged
merged 21 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ test-api:
./api-test/tester -expectedStatus=401 REQUEST GET $(URL)/lpas/$(LPA_UID) '' && \
cat ./docs/example-lpa.json | ./api-test/tester -jwtSecret=$(JWT_SECRET_KEY) -expectedStatus=201 REQUEST PUT $(URL)/lpas/$(LPA_UID) "`xargs -0`" && \
./api-test/tester -jwtSecret=$(JWT_SECRET_KEY) -expectedStatus=400 REQUEST PUT $(URL)/lpas/$(LPA_UID) '{"version":"2"}' && \
./api-test/tester -jwtSecret=$(JWT_SECRET_KEY) -expectedStatus=201 REQUEST POST $(URL)/lpas/$(LPA_UID)/updates '{"type":"CHANGE_NAME","changes":[{"key":"/donor/surname","old":"Zoller","new":"Kjar"}]}' && \
cat ./docs/certificate-provider-change.json | ./api-test/tester -jwtSecret=$(JWT_SECRET_KEY) -expectedStatus=201 REQUEST POST $(URL)/lpas/$(LPA_UID)/updates "`xargs -0`" && \
./api-test/tester -jwtSecret=$(JWT_SECRET_KEY) -expectedStatus=200 REQUEST GET $(URL)/lpas/$(LPA_UID) ''
.PHONY: test-api

Expand All @@ -41,11 +41,11 @@ create-tables:
--key-schema AttributeName=uid,KeyType=HASH \
--billing-mode PAY_PER_REQUEST

docker compose run --rm aws dynamodb describe-table --table-name events || \
docker compose run --rm aws dynamodb describe-table --table-name changes || \
docker compose run --rm aws dynamodb create-table \
--table-name events \
--attribute-definitions AttributeName=uid,AttributeType=S AttributeName=created,AttributeType=S \
--key-schema AttributeName=uid,KeyType=HASH AttributeName=created,KeyType=RANGE \
--table-name changes \
--attribute-definitions AttributeName=uid,AttributeType=S AttributeName=applied,AttributeType=S \
--key-schema AttributeName=uid,KeyType=HASH AttributeName=applied,KeyType=RANGE \
--billing-mode PAY_PER_REQUEST

run-structurizr:
Expand Down
6 changes: 6 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ version: "3.6"
services:
ddb:
image: amazon/dynamodb-local:latest
command: -jar DynamoDBLocal.jar -sharedDb -dbPath .
ports:
- "8000:8000"

lambda-create:
depends_on: [ddb]
Expand All @@ -17,6 +20,7 @@ services:
AWS_ACCESS_KEY_ID: X
AWS_SECRET_ACCESS_KEY: X
DDB_TABLE_NAME_DEEDS: deeds
DDB_TABLE_NAME_CHANGES: changes
JWT_SECRET_KEY: ${JWT_SECRET_KEY:-secret}
volumes:
- "./lambda/.aws-lambda-rie:/aws-lambda"
Expand All @@ -35,6 +39,7 @@ services:
AWS_ACCESS_KEY_ID: X
AWS_SECRET_ACCESS_KEY: X
DDB_TABLE_NAME_DEEDS: deeds
DDB_TABLE_NAME_CHANGES: changes
JWT_SECRET_KEY: ${JWT_SECRET_KEY:-secret}
volumes:
- "./lambda/.aws-lambda-rie:/aws-lambda"
Expand All @@ -53,6 +58,7 @@ services:
AWS_ACCESS_KEY_ID: X
AWS_SECRET_ACCESS_KEY: X
DDB_TABLE_NAME_DEEDS: deeds
DDB_TABLE_NAME_CHANGES: changes
JWT_SECRET_KEY: ${JWT_SECRET_KEY:-secret}
volumes:
- "./lambda/.aws-lambda-rie:/aws-lambda"
Expand Down
30 changes: 30 additions & 0 deletions docs/certificate-provider-change.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"type": "CERTIFICATE_PROVIDER_SIGN",
"changes": [
{
"key": "/certificateProvider/address/line1",
"new": "98 CVVVV",
"old": null
},
{
"key": "/certificateProvider/address/town",
"new": "Murkkkk Town",
"old": null
},
{
"key": "/certificateProvider/address/country",
"new": "GB",
"old": null
},
{
"key": "/certificateProvider/signedAt",
"new": "2024-01-13T22:00:00Z",
"old": null
},
{
"key": "/certificateProvider/contactLanguagePreference",
"new": "en",
"old": null
}
]
}
65 changes: 33 additions & 32 deletions docs/example-lpa.json
Original file line number Diff line number Diff line change
@@ -1,42 +1,43 @@
{
"lpaType": "personal-welfare",
"donor": {
"firstNames": "Homer",
"surname": "Zoller",
"dateOfBirth": "1960-04-06",
"email": "[email protected]",
"firstNames": "Feeg",
"lastName": "Bundlaaaa",
"address": {
"line1": "79 Bury Rd",
"town": "Hampton Lovett",
"postcode": "WR9 2PF",
"line1": "74 Cloob Close",
"town": "Mahhhhhhhhhh",
"country": "GB"
}
Comment on lines 6 to -12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This highlighted a bug: postcode should be required if country == GB. I've created a bug ticket for that.

Was there a reason to change this otherwise? Doesn't really matter, just interested.

Copy link
Contributor Author

@townxelliot townxelliot Feb 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gregtyler it was just that I created my own example JSON, then realised that there was already an example in the repo; so instead I just overwrote what was there with my newer and more correct version

},
"dateOfBirth": "1970-01-24",
"email": "[email protected]"
},
"attorneys": [
{
"firstNames": "Jake",
"surname": "Vallar",
"dateOfBirth": "2001-01-17",
"email": "[email protected]",
"status": "active",
"address": {
"line1": "71 South Western Terrace",
"town": "Milton",
"postcode": "6306",
"country": "AU"
}
},
{
"firstNames": "Tory",
"surname": "Lapolla",
"dateOfBirth": "1989-12-29",
"status": "replacement",
"firstNames": "Herman",
"lastName": "Seakrest",
"address": {
"line1": "184 Bayside Apartments",
"line2": "East Street",
"line3": "Saratosa",
"town": "Polebrook",
"country": "US"
}
"line1": "81 NighOnTimeWeBuiltIt Street",
"town": "Mahhhhhhhhhh",
"country": "GB"
},
"dateOfBirth": "1982-07-24",
"email": "[email protected]",
"status": "active"
}
]
],
"certificateProvider": {
"firstNames": "Vone",
"lastName": "Spust",
"address": {
"line1": "122111 Zonnington Way",
"town": "Mahhhhhhhhhh",
"country": "GB"
},
"channel": "online",
"email": "[email protected]"
},
"lifeSustainingTreatmentOption": "option-a",
"signedAt": "2024-01-10T23:00:00Z",
"certificateProviderNotRelatedConfirmedAt": "2024-01-11T22:00:00Z"
}

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.27.0
github.com/aws/aws-xray-sdk-go v1.8.3
github.com/golang-jwt/jwt/v5 v5.2.0
github.com/google/go-cmp v0.5.9
github.com/google/uuid v1.6.0
github.com/ministryofjustice/opg-go-common v0.0.0-20231128145056-24628fba649c
github.com/stretchr/testify v1.8.4
Expand Down
26 changes: 0 additions & 26 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,14 @@ github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1M
github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/aws/aws-lambda-go v1.43.0 h1:Tdu7SnMB5bD+CbdnSq1Dg4sM68vEuGIDcQFZ+IjUfx0=
github.com/aws/aws-lambda-go v1.43.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A=
github.com/aws/aws-lambda-go v1.44.0 h1:Xp9PANXKsSJ23IhE4ths592uWTCEewswPhSH9qpAuQQ=
github.com/aws/aws-lambda-go v1.44.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A=
github.com/aws/aws-lambda-go v1.45.0 h1:3xS35Dlc8ffmcwfcKTyqJGiMuL0UDvkQaVUrI5yHycI=
github.com/aws/aws-lambda-go v1.45.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A=
github.com/aws/aws-lambda-go v1.46.0 h1:UWVnvh2h2gecOlFhHQfIPQcD8pL/f7pVCutmFl+oXU8=
github.com/aws/aws-lambda-go v1.46.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A=
github.com/aws/aws-sdk-go v1.49.13 h1:f4mGztsgnx2dR9r8FQYa9YW/RsKb+N7bgef4UGrOW1Y=
github.com/aws/aws-sdk-go v1.49.13/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go v1.49.15 h1:aH9bSV4kL4ziH0AMtuYbukGIVebXddXBL0cKZ1zj15k=
github.com/aws/aws-sdk-go v1.49.15/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go v1.49.16 h1:KAQwhLg296hfffRdh+itA9p7Nx/3cXS/qOa3uF9ssig=
github.com/aws/aws-sdk-go v1.49.16/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go v1.49.17 h1:Cc+7LgPjKeJkF2SdNo1IkpQ5Dfl9HCZEVw9OP3CPuEI=
github.com/aws/aws-sdk-go v1.49.17/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go v1.49.21 h1:Rl8KW6HqkwzhATwvXhyr7vD4JFUMi7oXGAw9SrxxIFY=
github.com/aws/aws-sdk-go v1.49.21/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go v1.50.5 h1:H2Aadcgwr7a2aqS6ZwcE+l1mA6ZrTseYCvjw2QLmxIA=
github.com/aws/aws-sdk-go v1.50.5/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go v1.50.6 h1:FaXvNwHG3Ri1paUEW16Ahk9zLVqSAdqa1M3phjZR35Q=
github.com/aws/aws-sdk-go v1.50.6/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go v1.50.9 h1:yX66aKnEtRc/uNV/1EH8CudRT5aLwVwcSwTBphuVPt8=
github.com/aws/aws-sdk-go v1.50.9/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU=
github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4=
github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.12.14 h1:FpgWcv1aqU3xXbMVwEBr2sCeRT1Cctwqg/sWMI4wLoo=
github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.12.14/go.mod h1:J2zgl/oFM9OWQoaEATWvh426859hrB1cuVEqLgGpi+Q=
github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.12.16 h1:KZvXflfyoL43jhDe2tDHPeK9C+edHJl2Rb07N7Dq3qY=
github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.12.16/go.mod h1:SdkjT6MneWbTztIxA5cZ8QTvD4ASCeM7IhUkIIhvVa0=
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.26.8 h1:XKO0BswTDeZMLDBd/b5pCEZGttNXrzRUVtFvp2Ak/Vo=
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.26.8/go.mod h1:N5tqZcYMM0N1PN7UQYJNWuGyO886OfnMhf/3MAbqMcI=
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.27.0 h1:e/HPLjLas04wKnmCUSSXD44cYdVjT/Dcd9CkmlYNyNU=
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.27.0/go.mod h1:N5tqZcYMM0N1PN7UQYJNWuGyO886OfnMhf/3MAbqMcI=
github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.18.7 h1:srShyROqxzC7p18Ws8mqM2sqxJO/8L3Kpiqf+NboJLg=
Expand All @@ -54,8 +30,6 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
Expand Down
51 changes: 46 additions & 5 deletions internal/ddb/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,48 @@ import (
)

type Client struct {
ddb *dynamodb.DynamoDB
tableName string
ddb *dynamodb.DynamoDB
tableName string
changesTableName string
}

func (c *Client) PutChanges(ctx context.Context, data any, update shared.Update) error {
changesItem, err := dynamodbattribute.MarshalMap(map[string]interface{}{
"uid": update.Uid,
"applied": update.Applied,
"author": update.Author,
"type": update.Type,
"change": update.Changes,
})

item, err := dynamodbattribute.MarshalMap(data)
if err != nil {
return err
}

transactInput := &dynamodb.TransactWriteItemsInput{
TransactItems: []*dynamodb.TransactWriteItem{
// write the LPA to the deeds table
&dynamodb.TransactWriteItem{
Put: &dynamodb.Put{
TableName: aws.String(c.tableName),
Item: item,
},
},

// record the change
&dynamodb.TransactWriteItem{
Put: &dynamodb.Put{
TableName: aws.String(c.changesTableName),
Item: changesItem,
},
},
},
}

_, err = c.ddb.TransactWriteItemsWithContext(ctx, transactInput)

return err
}

func (c *Client) Put(ctx context.Context, data any) error {
Expand Down Expand Up @@ -54,13 +94,14 @@ func (c *Client) Get(ctx context.Context, uid string) (shared.Lpa, error) {
return lpa, err
}

func New(endpoint, tableName string) *Client {
func New(endpoint, tableName string, changesTableName string) *Client {
sess := session.Must(session.NewSession())
sess.Config.Endpoint = &endpoint

c := &Client{
ddb: dynamodb.New(sess),
tableName: tableName,
ddb: dynamodb.New(sess),
tableName: tableName,
changesTableName: changesTableName,
}

xray.AWS(c.ddb.Client)
Expand Down
25 changes: 13 additions & 12 deletions internal/shared/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ var validIssuers []string = []string{
mrlpa,
}

type lpaStoreClaims struct {
type LpaStoreClaims struct {
jwt.RegisteredClaims
}

// note that default validation for RegisteredClaims checks exp is in the future
func (l lpaStoreClaims) Validate() error {
func (l LpaStoreClaims) Validate() error {
// validate issued at (iat)
iat, err := l.GetIssuedAt()
if err != nil {
Expand Down Expand Up @@ -92,36 +92,37 @@ var bearerRegexp = regexp.MustCompile("^Bearer[ ]+")

// verify JWT from event header
// returns true if verified, false otherwise
func (v JWTVerifier) VerifyHeader(event events.APIGatewayProxyRequest) bool {
func (v JWTVerifier) VerifyHeader(event events.APIGatewayProxyRequest) (*LpaStoreClaims, error) {
jwtHeaders := GetEventHeader("X-Jwt-Authorization", event)

if len(jwtHeaders) < 1 {
return false
return nil, fmt.Errorf("Invalid X-Jwt-Authorization header")
}

tokenStr := bearerRegexp.ReplaceAllString(jwtHeaders[0], "")
if v.verifyToken(tokenStr) != nil {
return false
claims, err := v.verifyToken(tokenStr)
if err != nil {
return nil, err
}

return true
return claims, nil
}

// tokenStr is the JWT token, minus any "Bearer: " prefix
func (v JWTVerifier) verifyToken(tokenStr string) error {
lsc := lpaStoreClaims{}
func (v JWTVerifier) verifyToken(tokenStr string) (*LpaStoreClaims, error) {
lsc := LpaStoreClaims{}

parsedToken, err := jwt.ParseWithClaims(tokenStr, &lsc, func(token *jwt.Token) (interface{}, error) {
return v.secretKey, nil
})

if err != nil {
return err
return nil, err
}

if !parsedToken.Valid {
return fmt.Errorf("Invalid JWT")
return nil, fmt.Errorf("Invalid JWT")
}

return nil
return &lsc, nil
}
Loading
Loading