Skip to content

Commit

Permalink
get cap cid and log it, for later retrieval of cacao (#1153)
Browse files Browse the repository at this point in the history
* extract the cacao cid url from signature, or we may use root.tip

Note this is the url, not the actual cacao.  will retrieve async from ipfs

* decode the protected header, add tests

* index not object

* typos - still some issues

* the positive test works now, but invalid carfiles pass?

* move invalid carfile tests to separate PR

* Revert "move invalid carfile tests to separate PR" (#1162)

* Revert "move invalid carfile tests to separate PR"

This reverts commit d82ee7b.

* invalid car file produces isLeft; cannot decode throws error

* ok an invalid carfile has isLeft, but what about some random string?

* remove duplicate coverage test
  • Loading branch information
gvelez17 authored Sep 12, 2023
1 parent 855c1b4 commit 07c3509
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 7 deletions.
38 changes: 37 additions & 1 deletion src/ancillary/__tests__/anchor-request-params-parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { bases } from 'multiformats/basics'
import { GenesisFields } from '../../models/metadata.js'
import { asDIDString } from '@ceramicnetwork/codecs'
import { mockRequest } from '../../controllers/__tests__/mock-request.util.js'
import { isRight, type Right } from 'codeco'
import { isRight, isLeft, type Right } from 'codeco'

const FAKE_SIGNED_STREAM_ID = StreamID.fromString(
'k2t6wzhkhabz5h9xxyrc6qoh1mcj6b0ul90xxkoin4t5bns89e3vh0gyyy1exj'
Expand All @@ -27,6 +27,9 @@ const FAKE_UNSIGNED_TIP = toCID('bafyreigoetnvcimetv4n3dh3pxjeg7x2vym6bjgf7pxjcb

const TIMESTAMP_ISO = '2023-01-25T17:32:42.971Z'

const FAKE_CAPCID='bafyreie2r6tmsvwfatlhpxxqm53npwww36pejsbna36swgvhqm7ukzq3ka'


const LEGACY_REQUEST_EXAMPLE = mockRequest({
headers: {
'Content-Type': 'application/json',
Expand Down Expand Up @@ -56,6 +59,25 @@ const CAR_FILE_REQUEST_EXAMPLE_UNSIGNED_GENESIS = mockRequest({
),
})

const CAR_FILE_REQUEST_EXAMPLE_SIGNED_GENESIS_WITH_CAPCID = mockRequest({
headers: {
'Content-Type': 'application/vnd.ipld.car',
},
body: bases['base64url'].decode('uOqJlcm9vdHOB2CpYJQABcRIgwcxsif-rrekn_a2-Bhct6FEDdHK6u3AJb3_B6tvawXFndmVyc2lvbgGqAQFxEiDBzGyJ_6ut6Sf9rb4GFy3oUQN0crq7cAlvf8Hq29rBcaNjdGlw2CpYJgABhQESINQg_eQxpZ-MKScNxNX4g_mokMkhcrlm3iikxiMgcW1VaHN0cmVhbUlkWCjOAQABhQESINQg_eQxpZ-MKScNxNX4g_mokMkhcrlm3iikxiMgcW1VaXRpbWVzdGFtcHgYMjAyMy0wOS0wOFQxNToxMDoyNi43ODBahQMBhQESINQg_eQxpZ-MKScNxNX4g_mokMkhcrlm3iikxiMgcW1VomdwYXlsb2FkWCQBcRIgkwe64uSAOO9atHATIYB1C7U-K7UfhS3FGU_WiXHyL65qc2lnbmF0dXJlc4GiaXByb3RlY3RlZFjMeyJhbGciOiJFZERTQSIsImNhcCI6ImlwZnM6Ly9iYWZ5cmVpZTJyNnRtc3Z3ZmF0bGhweHhxbTUzbnB3d3czNnBlanNibmEzNnN3Z3ZocW03dWt6cTNrYSIsImtpZCI6ImRpZDprZXk6ejZNa3F1REdwdGUzNFN6akxrNm5KNkxXc0hIS1Q1RVBndG5xdHo5cFV5QzQ1SGVNI3o2TWtxdURHcHRlMzRTempMazZuSjZMV3NISEtUNUVQZ3RucXR6OXBVeUM0NUhlTSJ9aXNpZ25hdHVyZVhAK4M_E69hCRw-WOGPMAr9TGtj8K5qyl0BkFuqJRxRqOlvbj-mh9O5hbZDfJQM5cVx6BQp7nBiMNWJUgRKwXhLDbABAXESIJMHuuLkgDjvWrRwEyGAdQu1Piu1H4UtxRlP1olx8i-uomRkYXRhoWVoZWxsb3QxLTAuMzcxNDMxMjk4MjUwNzE5M2ZoZWFkZXKiZnVuaXF1ZXBvOTArZUNSUlJrVUpGNUJia2NvbnRyb2xsZXJzgXg7ZGlkOnBraDplaXAxNTU6NToweEY2ZjcyMWQ4MzdjMzI5ZGZiRkZkNzhjYWRCNDk0YWYxOTg3OTg3NEaKBAFxEiCaj6bJVsUE1nfe8Gd219rW355EyC0G_Ssap4M_RWYbUKNhaKFhdGdlaXA0MzYxYXCpY2F1ZHg4ZGlkOmtleTp6Nk1rcXVER3B0ZTM0U3pqTGs2bko2TFdzSEhLVDVFUGd0bnF0ejlwVXlDNDVIZU1jZXhweBgyMDIzLTA5LTE1VDE1OjEwOjI2LjU4MVpjaWF0eBgyMDIzLTA5LTA4VDE1OjEwOjI2LjU4MVpjaXNzeDtkaWQ6cGtoOmVpcDE1NTo1OjB4RjZmNzIxZDgzN2MzMjlkZmJGRmQ3OGNhZEI0OTRhZjE5ODc5ODc0RmVub25jZWprbE82clBaRW1sZmRvbWFpbmR0ZXN0Z3ZlcnNpb25hMWlyZXNvdXJjZXOBa2NlcmFtaWM6Ly8qaXN0YXRlbWVudHg8R2l2ZSB0aGlzIGFwcGxpY2F0aW9uIGFjY2VzcyB0byBzb21lIG9mIHlvdXIgZGF0YSBvbiBDZXJhbWljYXOiYXN4hDB4YmNjZDY4ZDI3NTRlNDc0NGE4YTFkMGZlYzBiMmM2YWZlZjM1MTE3Yzg0NzRmZjE0NTczNTg3NzQ2MjA0ZTQ5YTdmYTFlYmNhYzNiZmJkYjY4MTM4ZDJiYTllN2Q3Y2Q5Yzc1ZjU1MmQxYTI3Yzk4ZmQ5OTMzYmI1NmFjMGU5ZTAxYmF0ZmVpcDE5MQ'
),
})


const CAR_FILE_INVALID = mockRequest({
headers: {
'Content-Type': 'application/vnd.ipld.car',
},
body: bases['base64url'].decode(
'uQ3JlYXRlZEJ5Q2hhdEdQVDRZb3VjYW5Vc2VUaGlzU3RyaW5n'
),
})


const CAR_FILE_FAKE_GENESIS_FIELDS: GenesisFields = {
controllers: [asDIDString('did:pkh:eip155:1:0x926eeb192c18b7be607a7e10c8e7a7e8d9f70742')],
model: StreamID.fromBytes(
Expand Down Expand Up @@ -97,4 +119,18 @@ describe('AnchoRequestParamsParser', () => {
expect(params.timestamp).toEqual(new Date(TIMESTAMP_ISO))
expect((params as RequestAnchorParamsV2).genesisFields).toEqual(CAR_FILE_FAKE_GENESIS_FIELDS)
})

test('parses CAR file with signed genesis with capCID properly', () => {
const validation = parser.parse(CAR_FILE_REQUEST_EXAMPLE_SIGNED_GENESIS_WITH_CAPCID as ExpReq)
expect(isRight(validation)).toEqual(true)

const params: RequestAnchorParams = (validation as Right<RequestAnchorParams>).right
expect(params.capCID).toEqual(FAKE_CAPCID)
})

test('isleft indicates invalid car file', () => {
const validation = parser.parse(CAR_FILE_INVALID as ExpReq)
expect(isLeft(validation)).toBeTruthy()
})

})
26 changes: 20 additions & 6 deletions src/ancillary/anchor-request-params-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import type { Request as ExpReq } from 'express'
import type { CID } from 'multiformats/cid'
import { CARFactory, type CAR } from 'cartonne'
import { ServiceMetrics as Metrics } from '@ceramicnetwork/observability'
import { base64urlToJSON } from '@ceramicnetwork/common'
import { METRIC_NAMES } from '../settings.js'
import * as DAG_JOSE from 'dag-jose'
import { GenesisFields } from '../models/metadata.js'
import { IpfsGenesis } from '../services/metadata-service.js'
import { logger } from '../logger/index.js'
import {
uint8array,
cid,
Expand All @@ -22,7 +24,6 @@ import {
isLeft,
decode,
validate,
type,
union,
type TypeOf,
type Decoder,
Expand Down Expand Up @@ -53,11 +54,12 @@ const RequestAnchorParamsV2Root = strict({
/**
* Used to encode request params for logging purposes
*/
export const RequestAnchorParamsV2 = type({
export const RequestAnchorParamsV2 = sparse({
streamId: streamIdAsString,
timestamp: date,
cid: cidAsString,
genesisFields: GenesisFields,
capCID: optional(cidAsString)
})

export type RequestAnchorParamsV2 = TypeOf<typeof RequestAnchorParamsV2>
Expand Down Expand Up @@ -86,7 +88,7 @@ export class AnchorRequestCarFileDecoder implements Decoder<Uint8Array, RequestA
if (isLeft(rootE)) return context.failures(rootE.left)
const root = rootE.right
const genesisCid = root.streamId.cid
const maybeGenesisRecord = this.retrieveGenesisRecord(genesisCid, carFile)
const [maybeGenesisRecord, capCID] = this.retrieveGenesisRecord(genesisCid, carFile)
const genesisRecord = decode(IpfsGenesis, maybeGenesisRecord)
const genesisFields = genesisRecord.header

Expand All @@ -95,20 +97,32 @@ export class AnchorRequestCarFileDecoder implements Decoder<Uint8Array, RequestA
timestamp: root.timestamp,
cid: root.tip,
genesisFields: genesisFields,
capCID: capCID,
})
} catch (e: any) {
const message = e.message || String(e)
return context.failure(`Can not decode CAR file: ${message}`)
}
}

private retrieveGenesisRecord(genesisCid: CID, carFile: CAR): unknown {
private retrieveGenesisRecord(genesisCid: CID, carFile: CAR): [unknown, CID | undefined] {
switch (genesisCid.code) {
case DAG_CBOR_CODE:
return carFile.get(genesisCid)
return [carFile.get(genesisCid), undefined]
case DAG_JOSE_CODE: {
const genesisJWS = carFile.get(genesisCid)
return carFile.get(genesisJWS.link)
let capCID = undefined
const protectedHeader = genesisJWS.signatures[0].protected
try {
const capIPFSUri = base64urlToJSON(protectedHeader)['cap']
if (capIPFSUri) {
capCID = capIPFSUri.replace('ipfs://', '')
}
} catch (e:any) {
const message = e.message || String(e)
logger.warn(`Unable to decode protectedHeader: ${message}`)
}
return [carFile.get(genesisJWS.link), capCID]
}
default:
throw new Error(`Unsupported codec ${genesisCid.code} for genesis CID ${genesisCid}`)
Expand Down
1 change: 1 addition & 0 deletions src/services/request-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export class RequestService {
model: genesisFields?.model,
stream: request.streamId,
origin: request.origin,
cap_cid: 'capCID' in params ? params.capCID : '',
};

Metrics.count(METRIC_NAMES.WRITE_TOTAL_TSDB, 1, logData)
Expand Down

0 comments on commit 07c3509

Please sign in to comment.