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

Attestation service pepper verification #8692

Merged
merged 59 commits into from
Feb 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
c87ed6a
update signer dependency
emilhotkowski Jul 8, 2021
ada7e0b
Merge branch 'master' of https://github.com/celo-org/celo-monorepo
emilhotkowski Jul 16, 2021
5d703ab
Merge branch 'master' of https://github.com/celo-org/celo-monorepo
emilhotkowski Jul 19, 2021
aa7eb53
Merge branch 'master' of https://github.com/celo-org/celo-monorepo
emilhotkowski Jul 21, 2021
743e639
Merge branch 'master' of https://github.com/celo-org/celo-monorepo
emilhotkowski Jul 26, 2021
6f1b567
Merge branch 'master' of https://github.com/celo-org/celo-monorepo
emilhotkowski Jul 29, 2021
9adbfb6
Merge branch 'master' of https://github.com/celo-org/celo-monorepo
emilhotkowski Aug 16, 2021
196de93
Merge branch 'master' of https://github.com/celo-org/celo-monorepo
emilhotkowski Aug 18, 2021
c200a77
Added fallback for signers.
emilhotkowski Aug 19, 2021
cb54dab
Merge branch 'master' into emilhotkowski/front-door-fallback
emilhotkowski Aug 19, 2021
9ad1f54
Added test and options to Circuit Breaker
emilhotkowski Aug 20, 2021
7c3c3ce
Merge branch 'emilhotkowski/front-door-fallback' of https://github.co…
emilhotkowski Aug 20, 2021
729ef0a
Removed console.log
emilhotkowski Aug 20, 2021
398c23c
Merge branch 'master' into emilhotkowski/front-door-fallback
emilhotkowski Aug 20, 2021
23a25b1
Added circuit breaker for every signer
emilhotkowski Aug 21, 2021
68a3116
Merge branch 'master' into emilhotkowski/front-door-fallback
emilhotkowski Aug 21, 2021
d97a7d6
Merge branch 'master' into emilhotkowski/front-door-fallback
emilhotkowski Aug 26, 2021
6c5a952
Corrected import in Combiner
emilhotkowski Aug 26, 2021
84b326c
Added tests
emilhotkowski Sep 9, 2021
d09d0a4
Merge remote-tracking branch 'origin/master' into emilhotkowski/attes…
emilhotkowski Sep 13, 2021
5ac686d
Added working package.json for new tests
emilhotkowski Sep 13, 2021
796a14c
Merge branch 'master' into emilhotkowski/attestation-service-pepper-v…
emilhotkowski Sep 14, 2021
8951a24
remove the 'd' package
emilhotkowski Sep 14, 2021
61d2275
Merge branch 'emilhotkowski/attestation-service-pepper-verification' …
emilhotkowski Sep 14, 2021
f899ee1
Change yarn lock
emilhotkowski Sep 14, 2021
7bd3125
Optinally verify pepper
emilhotkowski Sep 28, 2021
b9cb367
Merge branch 'master' into emilhotkowski/attestation-service-pepper-v…
emilhotkowski Sep 28, 2021
96f8bc7
Change verification method
emilhotkowski Oct 15, 2021
0a08b87
use unblinded signature
isabellewei Feb 2, 2022
6cc1701
Merge branch 'master' of github.com:celo-org/celo-monorepo into isabe…
isabellewei Feb 2, 2022
bdc3339
update types and tests
isabellewei Feb 2, 2022
655c32c
silently fail
isabellewei Feb 2, 2022
5efd8d7
fix dependency test
isabellewei Feb 8, 2022
97c93b8
Merge branch 'master' of github.com:celo-org/celo-monorepo into emilh…
isabellewei Feb 8, 2022
86dd13f
PR comments
isabellewei Feb 9, 2022
2d109aa
update dependency grpah
isabellewei Feb 10, 2022
af00bad
Merge branch 'master' of github.com:celo-org/celo-monorepo into emilh…
isabellewei Feb 10, 2022
f112091
fix build
isabellewei Feb 10, 2022
9dec778
fix build
isabellewei Feb 10, 2022
7f49d8e
add yarn lock
isabellewei Feb 10, 2022
1164b7e
update yarn.lock
isabellewei Feb 10, 2022
7d36f5f
passing test + dynamic ODIS key
isabellewei Feb 17, 2022
c7524e1
update docker
isabellewei Feb 21, 2022
d92dae5
Merge branch 'master' of github.com:celo-org/celo-monorepo into emilh…
isabellewei Feb 21, 2022
ce3b7ff
update dependency graph
isabellewei Feb 21, 2022
729fb4e
update docker
isabellewei Feb 21, 2022
731f790
update env function
isabellewei Feb 21, 2022
c9b978c
Merge branch 'master' into emilhotkowski/attestation-service-pepper-v…
isabellewei Feb 24, 2022
8e6367c
fix docker
isabellewei Feb 25, 2022
a45f717
Merge branch 'emilhotkowski/attestation-service-pepper-verification' …
isabellewei Feb 25, 2022
7115b0a
update env-tests
isabellewei Feb 25, 2022
dd4280e
update celotool docker
isabellewei Feb 25, 2022
4055dde
update dep graph
isabellewei Feb 25, 2022
7b11c76
update metrics
isabellewei Feb 25, 2022
a65440c
update yaml
isabellewei Feb 25, 2022
f31fc84
Merge branch 'master' into emilhotkowski/attestation-service-pepper-v…
isabellewei Feb 25, 2022
7b69721
update yaml
isabellewei Feb 26, 2022
29d6153
Merge branch 'emilhotkowski/attestation-service-pepper-verification' …
isabellewei Feb 26, 2022
933d7ca
Merge branch 'master' into emilhotkowski/attestation-service-pepper-v…
isabellewei Feb 28, 2022
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
4 changes: 3 additions & 1 deletion dependency-graph.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
"location": "packages/attestation-service",
"dependencies": [
"@celo/contractkit",
"@celo/identity",
"@celo/keystores",
"@celo/utils"
"@celo/phone-utils"
]
},
"celo-azure-build": {
Expand Down Expand Up @@ -58,6 +59,7 @@
"@celo/connect",
"@celo/contractkit",
"@celo/identity",
"@celo/phone-utils",
"@celo/utils"
]
},
Expand Down
6 changes: 6 additions & 0 deletions dockerfiles/attestation-service/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ COPY packages/sdk/contractkit/package.json packages/sdk/contractkit/
COPY packages/sdk/keystores/package.json packages/sdk/keystores/
COPY packages/attestation-service/package.json packages/attestation-service/
COPY packages/flake-tracker/package.json packages/flake-tracker/package.json
COPY packages/sdk/identity/package.json packages/sdk/identity/
COPY packages/sdk/phone-utils/package.json packages/sdk/phone-utils/package.json
COPY packages/phone-number-privacy/common/package.json packages/phone-number-privacy/common/

RUN yarn install --frozen-lockfile --network-timeout 100000 && yarn cache clean

Expand All @@ -37,6 +40,9 @@ COPY packages/sdk/contractkit packages/sdk/contractkit/
COPY packages/sdk/keystores packages/sdk/keystores/
COPY packages/attestation-service packages/attestation-service/
COPY packages/flake-tracker packages/flake-tracker
COPY packages/sdk/identity packages/sdk/identity
COPY packages/sdk/phone-utils packages/sdk/phone-utils/
COPY packages/phone-number-privacy/common packages/phone-number-privacy/common

ENV NODE_ENV production

Expand Down
2 changes: 2 additions & 0 deletions dockerfiles/celotool/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ COPY packages/sdk/wallets/wallet-local/package.json packages/sdk/wallets/wallet-
COPY packages/typescript/package.json packages/typescript/
COPY patches/ patches/
COPY scripts/ scripts/
COPY packages/sdk/phone-utils/package.json packages/sdk/phone-utils/package.json

RUN yarn install --network-timeout 100000 --frozen-lockfile && yarn cache clean

Expand All @@ -54,6 +55,7 @@ COPY packages/sdk/utils packages/sdk/utils/
COPY packages/sdk/wallets/wallet-base packages/sdk/wallets/wallet-base/
COPY packages/sdk/wallets/wallet-local packages/sdk/wallets/wallet-local/
COPY packages/typescript packages/typescript/
COPY packages/sdk/phone-utils packages/sdk/phone-utils/

RUN yarn build

Expand Down
3 changes: 3 additions & 0 deletions packages/attestation-service/config/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,6 @@ APP_SIGNATURE=x

# Phone number (prefixed with "+") for test-send-sms-twilio script
# TEST_SMS_RECIPIENT=x

# mainnet, alfajores, or alfajoresstaging, default is mainnet
# NETWORK=x
3 changes: 2 additions & 1 deletion packages/attestation-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
},
"dependencies": {
"@celo/contractkit": "1.5.3-dev",
"@celo/identity": "1.5.3-dev",
"@celo/keystores": "1.5.3-dev",
isabellewei marked this conversation as resolved.
Show resolved Hide resolved
"@celo/utils": "1.5.3-dev",
"@celo/phone-utils": "1.5.3-dev",
"bignumber.js": "^9.0.0",
"body-parser": "1.19.0",
"bunyan": "1.8.12",
Expand Down
2 changes: 1 addition & 1 deletion packages/attestation-service/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
AttestationRequestType,
AttestationServiceTestRequestType,
GetAttestationRequestType,
} from '@celo/utils/lib/io'
} from '@celo/phone-utils/lib/io'
import express from 'express'
import rateLimit from 'express-rate-limit'
import requestIdMiddleware from 'express-request-id'
Expand Down
4 changes: 4 additions & 0 deletions packages/attestation-service/src/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ export const Counters = {
labelNames: ['country', 'type'],
help: 'Counter for requests by country and type of phone number',
}),
attestationRequestsDidNotProvideSignature: new Counter({
name: 'attestation_requests_did_not_provide_signature',
help: 'Counter for the number of requests which did not provide a phone number signature',
}),
}

export const Gauges = {
Expand Down
43 changes: 41 additions & 2 deletions packages/attestation-service/src/requestHandlers/attestation.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import { AttestationState } from '@celo/contractkit/lib/wrappers/Attestations'
import { OdisUtils } from '@celo/identity'
import { getPepperFromThresholdSignature } from '@celo/identity/lib/odis/phone-number-identifier'
import { AttestationRequest } from '@celo/phone-utils/lib/io'
import { AttestationUtils, PhoneNumberUtils } from '@celo/utils'
import { eqAddress } from '@celo/utils/lib/address'
import { sleep } from '@celo/utils/lib/async'
import { AttestationRequest } from '@celo/utils/lib/io'
import Logger from 'bunyan'
import { randomBytes } from 'crypto'
import express from 'express'
import { findAttestationByKey, makeSequelizeLogger, SequelizeLogger, useKit } from '../db'
import { getAccountAddress, getAttestationSignerAddress, isDevMode } from '../env'
import {
fetchEnvOrDefault,
getAccountAddress,
getAttestationSignerAddress,
isDevMode,
} from '../env'
import { Counters } from '../metrics'
import { AttestationKey, AttestationModel } from '../models/attestation'
import { ErrorWithResponse, respondWithAttestation, respondWithError, Response } from '../request'
Expand All @@ -16,6 +23,11 @@ import { obfuscateNumber } from '../sms/base'

const ATTESTATION_ERROR = 'Valid attestation could not be provided'
const NO_INCOMPLETE_ATTESTATION_FOUND_ERROR = 'No incomplete attestation found'
export const INVALID_SIGNATURE_ERROR = 'Signature is invalid'

const odisPubKey = OdisUtils.Query.getServiceContext(fetchEnvOrDefault('NETWORK', 'mainnet'))
.odisPubKey
const thresholdBls = require('blind-threshold-bls')

function toBase64(str: string) {
return Buffer.from(str.slice(2), 'hex').toString('base64')
Expand Down Expand Up @@ -78,6 +90,8 @@ class AttestationRequestHandler {
logging: this.sequelizeLogger,
})

await this.verifyPepperIfApplicable()
alecps marked this conversation as resolved.
Show resolved Hide resolved

// Re-requests for existing attestations skip the on-chain check.
if (attestation) {
Counters.attestationRequestsRerequest.inc()
Expand Down Expand Up @@ -221,6 +235,31 @@ class AttestationRequestHandler {

return attestation
}

private async verifyPepperIfApplicable(): Promise<void> {
alecps marked this conversation as resolved.
Show resolved Hide resolved
if (this.attestationRequest.phoneNumberSignature && this.attestationRequest.salt) {
const sigBuf = Buffer.from(this.attestationRequest.phoneNumberSignature, 'base64')

try {
await thresholdBls.verify(
Buffer.from(odisPubKey, 'base64'),
Buffer.from(this.attestationRequest.phoneNumber, 'base64'),
sigBuf
)

const pepper = getPepperFromThresholdSignature(sigBuf)
if (pepper !== this.attestationRequest.salt) {
isabellewei marked this conversation as resolved.
Show resolved Hide resolved
isabellewei marked this conversation as resolved.
Show resolved Hide resolved
this.logger.error('Pepper is invalid')
// temporarily only silently fail, so as not to block users
// throw new ErrorWithResponse('Pepper is invalid', 422)
}
} catch (e) {
this.logger.error('Cannot get phone number from signature', e)
throw new ErrorWithResponse(INVALID_SIGNATURE_ERROR, 422)
}
}
Counters.attestationRequestsDidNotProvideSignature.inc()
}
}

export async function handleAttestationRequest(
Expand Down
115 changes: 82 additions & 33 deletions packages/attestation-service/test/requestHandlers/attestation.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,38 @@
import { handleAttestationRequest } from '../../src/requestHandlers/attestation'
import { anyNumber, capture, instance, mock, reset, verify, when } from 'ts-mockito'
import { Response } from '../../src/request'
import { Request } from 'express'
import * as Logger from 'bunyan'
import { isValidAddress, toChecksumAddress } from 'ethereumjs-util'
import { Request } from 'express'
import { anyNumber, capture, instance, mock, reset, verify, when } from 'ts-mockito'
import { findAttestationByKey } from '../../src/db'
import { Response } from '../../src/request'
import {
handleAttestationRequest,
INVALID_SIGNATURE_ERROR,
} from '../../src/requestHandlers/attestation'
import { rerequestAttestation } from '../../src/sms'

jest.mock('ethereumjs-util')
const isValidAddressMock = isValidAddress as jest.Mock
const toChecksumAddressMock = toChecksumAddress as jest.Mock
import ethereumJsUtil = require('ethereumjs-util')
const isValidAddressMock = jest.spyOn(ethereumJsUtil, 'isValidAddress')
const toChecksumAddressMock = jest.spyOn(ethereumJsUtil, 'toChecksumAddress')

jest.mock('../../src/db')
const findAttestationByKeyMock = findAttestationByKey as jest.Mock

jest.mock('../../src/sms')
const rerequestAttestationMock = rerequestAttestation as jest.Mock

jest.mock('@celo/identity', () => {
const OdisUtils = {
Query: {
getServiceContext: () => {
return {
odisPubKey:
'ru+9GmEsBi+/SHtNc4lBwR+evpvcVLcmVDYhzyveWXVwaN7EdUGF+GgUvOMMqpUAaxQl+4DkgtbTP4CIFFAUyGnZF0nRLqo64PVSv/mrGrTet0ej5cJeS1Fla+n8o5sB',
}
},
},
}
return { OdisUtils }
})

describe('Attestation request handler', () => {
const requestMock = mock<Request>()
const responseMock = mock<Response>()
Expand Down Expand Up @@ -59,6 +75,7 @@ describe('Attestation request handler', () => {
salt: 'salt',
securityCodePrefix: 'p',
smsRetrieverAppSig: 'sig',
phoneNumberSignature: undefined,
})

expect(findAttestationByKeyMock).toBeCalledTimes(1)
Expand All @@ -81,6 +98,7 @@ describe('Attestation request handler', () => {
salt: 'salt',
securityCodePrefix: '',
smsRetrieverAppSig: 'sig',
phoneNumberSignature: undefined,
})

expect(findAttestationByKeyMock).toBeCalledTimes(0)
Expand All @@ -106,6 +124,7 @@ describe('Attestation request handler', () => {
salt: 'salt',
securityCodePrefix: 'p',
smsRetrieverAppSig: 'sig',
phoneNumberSignature: undefined,
})

expect(findAttestationByKeyMock).toBeCalledTimes(0)
Expand All @@ -116,31 +135,60 @@ describe('Attestation request handler', () => {
expect(body['error']).toEqual(`Mismatching issuer, I am ${address}`)
})

// it("Should fail with 422 code when pepper didn't origin in odis", async () => {
// const address = '0x2F015C60E0be116B1f0CD534704Db9c92118FB6A';
// isValidAddressMock.mockReturnValue(true);
// toChecksumAddressMock.mockReturnValue(address);
// findAttestationByKeyMock.mockResolvedValue(null);
// const responseMockInstance = instance(responseMock);
// when(responseMock.status(anyNumber())).thenReturn(responseMockInstance);
//
// await handleAttestationRequest(instance(requestMock), responseMockInstance, {
// phoneNumber: '+14155550000',
// language: 'en',
// account: 'account',
// issuer: address,
// salt: 'salt',
// securityCodePrefix: 'p',
// smsRetrieverAppSig: 'sig'
// });
//
// expect(findAttestationByKeyMock).toBeCalledTimes(1);
// expect(rerequestAttestationMock).toBeCalledTimes(0);
// verify(responseMock.status(422)).once();
// const [body] = capture(responseMock.json).last();
// expect(body['success']).toBeFalsy();
// expect(body['error']).toEqual(`Mismatching issuer, I am ${address}`);
// })
it('Should fail with 422 code with wrong signature', async () => {
alecps marked this conversation as resolved.
Show resolved Hide resolved
const address = '0x2F015C60E0be116B1f0CD534704Db9c92118FB6A'
isValidAddressMock.mockReturnValue(true)
toChecksumAddressMock.mockReturnValue(address)
findAttestationByKeyMock.mockResolvedValue(null)
const responseMockInstance = instance(responseMock)
when(responseMock.status(anyNumber())).thenReturn(responseMockInstance)

await handleAttestationRequest(instance(requestMock), responseMockInstance, {
phoneNumber: '+14155550000',
language: 'en',
account: 'account',
issuer: address,
salt: 'salt',
securityCodePrefix: 'p',
smsRetrieverAppSig: 'sig',
phoneNumberSignature: 'wrongSignature',
})

expect(findAttestationByKeyMock).toBeCalledTimes(1)
expect(rerequestAttestationMock).toBeCalledTimes(0)
verify(responseMock.status(422)).once()
const [body] = capture(responseMock.json).last()
expect(body['success']).toBeFalsy()
expect(body['error']).toEqual(INVALID_SIGNATURE_ERROR)
})

it('Should verify correctly blinded signature and return attestation', async () => {
const address = '0x2F015C60E0be116B1f0CD534704Db9c92118FB6A'
isValidAddressMock.mockReturnValue(true)
toChecksumAddressMock.mockReturnValue(address)
const sampleAttestation = {
message: 'message',
failure: () => false,
}
findAttestationByKeyMock.mockResolvedValue(sampleAttestation)
rerequestAttestationMock.mockResolvedValue(sampleAttestation)
when(responseMock.status(anyNumber())).thenReturn(responseMock)

await handleAttestationRequest(instance(requestMock), instance(responseMock), {
phoneNumber: '+14155550000',
language: 'en',
account: 'account',
issuer: address,
salt: '4EcPvcixnoe/N',
securityCodePrefix: 'p',
smsRetrieverAppSig: 'sig',
phoneNumberSignature: 'xNOQZWEa6JIyuAhGf9H0Evjx60BB8PQ6E9498CTLod2PhYRypKMdwGVDtLNkptAA',
})

expect(findAttestationByKeyMock).toBeCalledTimes(1)
expect(rerequestAttestationMock).toBeCalledTimes(1)
verify(responseMock.status(200)).once()
})

it('Should fail with 500 code when validator address is invalid', async () => {
const address = '0x2F015C60E0be116B1f0CD534704Db9c92118FB6A'
Expand All @@ -157,6 +205,7 @@ describe('Attestation request handler', () => {
salt: 'salt',
securityCodePrefix: 'p',
smsRetrieverAppSig: 'sig',
phoneNumberSignature: undefined,
})

expect(findAttestationByKeyMock).toBeCalledTimes(0)
Expand Down
5 changes: 3 additions & 2 deletions packages/attestation-service/test/testSetup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = () => {
process.env.ODIS_PUBLIC_KEY = 'key'
process.env.NETWORK = 'mainnet'
process.env.ATTESTATION_SIGNER_ADDRESS = 'signerAddress'
process.env.CELO_VALIDATOR_ADDRESS = 'address'
process.env.CELO_VALIDATOR_ADDRESS = '0x2F015C60E0be116B1f0CD534704Db9c92118FB6A'
process.env.CELO_PROVIDERS = 'provider'
process.env.NODE_ENV = 'dev'
}
2 changes: 1 addition & 1 deletion packages/celotool/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,5 @@ a few useful commands to make running a node really easy.

#### MacOS Setup

- Install Helm 3.X (available on Homebrew)
- Install Helm 3.4 or higher (available on Homebrew)
To get past the Unidentified Developer error: open the directory containing helm, then ctrl-click helm and select Open then Open again. Repeat for tiller.
1 change: 1 addition & 0 deletions packages/env-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"@celo/base": "1.5.3-dev",
"@celo/connect": "1.5.3-dev",
"@celo/identity": "1.5.3-dev",
"@celo/phone-utils": "1.5.3-dev",
"bunyan": "1.8.12",
"bunyan-gke-stackdriver": "0.1.2",
"bunyan-debug-stream": "2.0.0",
Expand Down
3 changes: 2 additions & 1 deletion packages/env-tests/src/shared/attestation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import {
} from '@celo/contractkit/lib/wrappers/Attestations'
import { OdisUtils } from '@celo/identity'
import { AuthSigner } from '@celo/identity/lib/odis/query'
import { AttestationRequest } from '@celo/phone-utils/lib/io'
import { AttestationUtils, PhoneNumberUtils } from '@celo/utils'
import { concurrentMap, sleep } from '@celo/utils/lib/async'
import { AttestationRequest } from '@celo/utils/lib/io'
import Logger from 'bunyan'
import { sample } from 'lodash'
import moment from 'moment'
Expand Down Expand Up @@ -41,6 +41,7 @@ export async function requestAttestationsFromIssuers(
smsRetrieverAppSig: undefined,
securityCodePrefix: securityCode ? getSecurityCodePrefix(attestation.issuer) : undefined,
language: undefined,
phoneNumberSignature: undefined,
}

const response = await attestations.revealPhoneNumberToIssuer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ spec:
value: /root/.celo
- name: LOG_FORMAT
value: stackdriver
- name: NETWORK
value: alfajores
- name: NEXMO_KEY
valueFrom:
secretKeyRef:
Expand Down
2 changes: 2 additions & 0 deletions packages/sdk/phone-utils/src/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export const AttestationRequestType = t.type({
// if specified, the message sent will be short random number prefixed by this string
securityCodePrefix: t.union([t.undefined, t.string]),
language: t.union([t.undefined, t.string]),
// unblinded signature
phoneNumberSignature: t.union([t.undefined, t.string]),
alecps marked this conversation as resolved.
Show resolved Hide resolved
})

export type AttestationRequest = t.TypeOf<typeof AttestationRequestType>
Expand Down