Skip to content

Commit

Permalink
feat(apple): get pass details from downloads table (#6)
Browse files Browse the repository at this point in the history
Populate the pass template with details stored in the `downloads` table
  • Loading branch information
aahna-ashina committed Sep 9, 2022
1 parent cbfb085 commit 7e0beaf
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ describe('Send an Updated Pass', () => {
it('error when wrong request method (POST instead of GET)', () => {
cy.request({
method: 'POST',
url: '/api/apple/v1/passes/pass.org.passport.nation3/333',
url: '/api/apple/v1/passes/pass.org.passport.nation3/5',
failOnStatusCode: false
}).then((response) => {
expect(response.status).to.eq(401)
Expand All @@ -16,18 +16,21 @@ describe('Send an Updated Pass', () => {
it('error when authentication token missing in header', () => {
cy.request({
method: 'GET',
url: '/api/apple/v1/passes/pass.org.passport.nation3/333',
url: '/api/apple/v1/passes/pass.org.passport.nation3/5',
failOnStatusCode: false
}).then((response) => {
expect(response.status).to.eq(401)
expect(JSON.stringify(response.body)).to.contain('Request Not Authorized: Missing/empty header: Authorization')
})
})


/**
* A passport with ID 5 is expected to have been downloaded previously (see downloadPass.cy.ts).
*/
it('success when valid authentication token in header', () => {
cy.request({
method: 'GET',
url: '/api/apple/v1/passes/pass.org.passport.nation3/333',
url: '/api/apple/v1/passes/pass.org.passport.nation3/5',
headers: {
'Authorization': 'ApplePass 0x3fbeb3ae33af3fb33f3d33333303d333a333aff33f3133efbc3330333adb333a'
},
Expand All @@ -41,4 +44,18 @@ describe('Send an Updated Pass', () => {
})
})

it('error when serial number missing from `downloads` table', () => {
cy.request({
method: 'GET',
url: '/api/apple/v1/passes/pass.org.passport.nation3/55555',
headers: {
'Authorization': 'ApplePass 0x3fbeb3ae33af3fb33f3d33333303d333a333aff33f3133efbc3330333adb333a'
},
failOnStatusCode: false
}).then((response) => {
expect(response.status).to.eq(500)
expect(JSON.stringify(response.body)).to.contain('multiple (or no) rows returned')
})
})

export {}
12 changes: 8 additions & 4 deletions server/cypress/e2e/api/downloadPass.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe('/api/downloadPass', () => {
expect(response.status).to.eq(400)
expect(JSON.stringify(response.body)).to.contain('Invalid address')
})
}),
})

it('error when invalid address', () => {
cy.request({
Expand All @@ -18,7 +18,7 @@ describe('/api/downloadPass', () => {
expect(response.status).to.eq(400)
expect(JSON.stringify(response.body)).to.contain('Invalid address')
})
}),
})

it('error when missing signature', () => {
cy.request({
Expand All @@ -28,7 +28,7 @@ describe('/api/downloadPass', () => {
expect(response.status).to.eq(400)
expect(JSON.stringify(response.body)).to.contain('Invalid signature')
})
}),
})

it('error when invalid signature', () => {
cy.request({
Expand All @@ -38,8 +38,12 @@ describe('/api/downloadPass', () => {
expect(response.status).to.eq(400)
expect(JSON.stringify(response.body)).to.contain('Invalid signature')
})
}),
})

/**
* The address 0x394b00B5De4E6f30292aCaC37f810Dd0672E211E is the holder of a passport with ID 5:
* https://goerli.etherscan.io/token/0x51f728c58697aff9582cfde3cbd00ec83e9ae7fc?a=0x394b00b5de4e6f30292acac37f810dd0672e211e
*/
it('success when valid address and signature', () => {
cy.request({
url: '/api/downloadPass?address=0x394b00B5De4E6f30292aCaC37f810Dd0672E211E&signature=0xeec065511291b0f3294a8f20a67bffd1a9ad11f0d44d68e8a324c91402ed0dd26fd27400af82325ec82d6fe5cdc0b167f1be0e18dd22d0e4865015608c050d7e1c',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,32 +44,52 @@ export default function handler(req: NextApiRequest, res: NextApiResponse) {
// Authenticate the request using a shared secret
// TODO

// Populate the pass template
const platform: Platform = Platform.Apple
const templateVersion: number = config.appleTemplateVersion
const passportID: string = String(serialNumber)
const issueDateTimestamp: number = 0 // TODO
const address: string = '<address>' // TODO
const ensName: string = '<ensName>' // TODO
const filePath: string = Passes.generatePass(
platform,
templateVersion,
passportID,
issueDateTimestamp,
address,
ensName
)
console.log('filePath:', filePath)
// Lookup the pass details stored in the downloads table when
// the pass for this address was last downloaded.
supabase
.from('downloads')
.select('*')
.eq('passport_id', serialNumber)
.order('id', { ascending: false })
.limit(1)
.single()
.then((result: any) => {
console.log('result:', result)

// Return the updated pass
const fileName = `passport_${address}_v${templateVersion}.pkpass`
console.log('fileName:', fileName)
res.setHeader('Last-Modified', `v${config.appleTemplateVersion}`)
res.setHeader('Content-Disposition', `attachment;filename=${fileName}`)
res.setHeader('Content-Type', 'application/vnd.apple.pkpass')
res.setHeader('Content-Length', fs.statSync(filePath).size)
const readStream = fs.createReadStream(filePath)
readStream.pipe(res)
if (result.error) {
res.status(500).json({
error: 'Internal Server Error: ' + result.error.message
})
} else {
// Populate the pass template
const platform: Platform = Platform.Apple
const templateVersion: number = config.appleTemplateVersion
const passportID: string = String(serialNumber)
const issueDate: Date = new Date(result.data['issue_date'])
const issueDateTimestamp: number = Math.round(issueDate.getTime() / 1000)
const address: string = result.data['address']
const ensName: string = result.data['ens_name']
const filePath: string = Passes.generatePass(
platform,
templateVersion,
passportID,
issueDateTimestamp,
address,
ensName
)
console.log('filePath:', filePath)

// Return the updated pass
const fileName = `passport_${address}_v${templateVersion}.pkpass`
console.log('fileName:', fileName)
res.setHeader('Last-Modified', `v${templateVersion}`)
res.setHeader('Content-Disposition', `attachment;filename=${fileName}`)
res.setHeader('Content-Type', 'application/vnd.apple.pkpass')
res.setHeader('Content-Length', fs.statSync(filePath).size)
const readStream = fs.createReadStream(filePath)
readStream.pipe(res)
}
})
} catch (err: any) {
console.error('[serialNumber].ts err:\n', err)
res.status(401).json({
Expand Down
51 changes: 28 additions & 23 deletions server/pages/api/downloadPass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,30 +114,35 @@ export default function handler(req: NextApiRequest, res: NextApiResponse) {
.insert(download)
.then((result: any) => {
console.log('then result:\n', result)
if (result.error) {
res.status(500).json({
error: 'Internal Server Error: ' + result.error.message
})
} else {
// Populate the pass template
const filePath: string = Passes.generatePass(
platform,
templateVersion,
passportID,
timestamp,
address,
ensName
)
console.log('filePath:', filePath)

// Serve the pass download to the user
const fileName = `passport_${address}_v${templateVersion}.pkpass`
console.log('fileName:', fileName)
res.setHeader(
'Content-Disposition',
`attachment;filename=${fileName}`
)
res.setHeader('Content-Type', 'application/vnd.apple.pkpass')
res.setHeader('Content-Length', fs.statSync(filePath).size)
const readStream = fs.createReadStream(filePath)
readStream.pipe(res)
}
})

// Populate the pass template
const filePath: string = Passes.generatePass(
platform,
templateVersion,
passportID,
timestamp,
address,
ensName
)
console.log('filePath:', filePath)

// Serve the pass download to the user
const fileName = `passport_${address}_v${templateVersion}.pkpass`
console.log('fileName:', fileName)
res.setHeader(
'Content-Disposition',
`attachment;filename=${fileName}`
)
res.setHeader('Content-Type', 'application/vnd.apple.pkpass')
res.setHeader('Content-Length', fs.statSync(filePath).size)
const readStream = fs.createReadStream(filePath)
readStream.pipe(res)
})
})
.catch((error: any) => {
Expand Down

0 comments on commit 7e0beaf

Please sign in to comment.