Skip to content
This repository was archived by the owner on Mar 12, 2021. It is now read-only.
Open
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
46 changes: 46 additions & 0 deletions app/api/controllers/attestation_data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as m from '@shared/models'

// perform attestation on an existing request
export const show = async (req: any, res: any) => {
const ad = await m.AttestationData.findById(req.params.attestation_data_id)

if (!ad) {
return res.status(404).json({success: false, message: 'Not found'})
}

const adRaw = ad.get({plain: true})

if (!ad.testChallenge(req.query.passphrase)) {
res
.status(401)
.json({success: false, message: 'Invalid credentials for attestation data'})
}

res.json({
success: true,
attestation_data: {
id: adRaw.id,
created: adRaw.created,
updated: adRaw.updated,
data: adRaw.datatype === 'text' ? adRaw.dtext : adRaw.dblob,
datatype: adRaw.datatype,
messageType: adRaw.messageType,
},
})
}

export const destroy = async (req: any, res: any) => {
const ad = await m.AttestationData.findById(req.params.attestation_data_id)

if (!ad) {
return res.status(404).json({success: false, message: 'Not found'})
}

if (!ad.testChallenge(req.query.passphrase)) {
res
.status(401)
.json({success: false, message: 'Invalid credentials for attestation data'})
}

await ad.destroy()
}
9 changes: 7 additions & 2 deletions app/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import * as express from 'express'
// import * as path from 'path'
import {env} from '@shared/environment'
import * as attCtrl from '@api/controllers/attestation'
import * as reqCtrl from '@api/controllers/request'
import {sha256} from 'ethereumjs-util'
import * as bodyParser from 'body-parser'

import * as attCtrl from '@api/controllers/attestation'
import * as reqCtrl from '@api/controllers/request'
import * as atDatCtrl from '@api/controllers/attestation_data'

const app = express()

interface IRequestWithRawBody extends express.Request {
Expand Down Expand Up @@ -49,6 +51,9 @@ app.post('/api/requests/send', reqCtrl.sendjob)
app.get('/api/attestations', attCtrl.show)
app.post('/api/attestations', attCtrl.perform)

app.get('/api/attestation_data/:attestation_data_id', atDatCtrl.show)
app.delete('/api/attestation_data/:attestation_data_id', atDatCtrl.destroy)

app.listen(13000, () => console.log('App listening on port 13000'))

export default app
30 changes: 30 additions & 0 deletions app/migrations/20180920161631-create-attestation-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict'
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.sequelize.query(`
CREATE TYPE "attestation_data_datatype"
AS ENUM('text','blob');

CREATE TABLE "attestationData" (
"id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
"created" timestamp without time zone DEFAULT now() NOT NULL,
"updated" timestamp without time zone DEFAULT now() NOT NULL,

"attestationId" uuid,
"messageType" enum_whisper_msg_types,

"datatype" attestation_data_datatype,
"dtext" text,
"dblob" blob,

"challenge" varchar(256)
);
`)
},
down: (queryInterface, Sequelize) => {
return queryInterface.sequelize.query(`
drop table AttestationData;
drop type attestation_data_datatype;
`)
},
}
2 changes: 2 additions & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
"@types/webpack": "3.8.1",
"@types/winston": "^2.3.7",
"async": "^2.6.0",
"attestations-lib": "https://github.com/hellobloom/attestations-lib/releases/download/v0.2.1/attestations-lib-v0.2.1.tgz",
"axios": "^0.18.0",
"babel-preset-stage-3": "^6.24.1",
"babel-register": "^6.26.0",
"bignumber.js": "^5.0.0",
Expand Down
4 changes: 2 additions & 2 deletions app/shared/attestations/validateAttestParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import {uniq} from 'lodash'
import {TUnvalidated} from '@shared/params/validation'
import * as U from '@shared/utils'
import {getFormattedTypedDataReleaseTokensLegacy} from '@shared/ethereum/signingLogic'
import {TAttestationDataJSONB} from '@shared/models/Attestation'
import {AttestationTypeID, HashingLogic} from '@bloomprotocol/attestations-lib'
import {IAttestationDataJSONB} from '@shared/models/Attestations/Attestation'
import BigNumber from 'bignumber.js'
import {requiredField} from '@shared/requiredField'
import {serverLogger} from '@shared/logger'
Expand All @@ -30,7 +30,7 @@ export interface IUnvalidatedAttestParams {
reward: BigNumber
paymentNonce: string
requesterSig: string
data: IAttestationDataJSONB
data: TAttestationDataJSONB
types: AttestationTypeID[]
requestNonce: string
subjectSig: string
Expand Down
19 changes: 16 additions & 3 deletions app/shared/attestations/validateJobDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import {
TAttestationTypeNames,
HashingLogic,
} from '@bloomprotocol/attestations-lib'
import {IAttestationDataJSONB} from '@shared/models/Attestations/Attestation'
import {
TMaybeAttestationDataJSONB,
TAttestationDataJSONB,
} from '@shared/models/Attestation'
import {requiredField} from '@shared/requiredField'
import {every} from 'lodash'

Expand All @@ -29,8 +32,18 @@ interface ISuccess {

export type TValidateJobDetailsOutput = IInvalidParamError | ISuccess

export interface IMaybeJobDetails {
data: TMaybeAttestationDataJSONB
requestNonce: string
types: number[]
subject: string
subjectSig: string
attester: string
requester: string
}

export interface IJobDetails {
data: IAttestationDataJSONB
data: TMaybeAttestationDataJSONB
requestNonce: string
types: number[]
subject: string
Expand Down Expand Up @@ -250,7 +263,7 @@ export const validateSubjectDataComponent = (
}

export const validateSubjectData = (
input: IAttestationDataJSONB,
input: TAttestationDataJSONB,
type: AttestationTypeID[]
): boolean => {
console.log(`validate input: ${JSON.stringify(input)}`)
Expand Down
2 changes: 2 additions & 0 deletions app/shared/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {toBuffer} from 'ethereumjs-util'
dotenv.config()

interface IEnvironmentConfig {
hostname: string
apiKey: string
appId: string
appPort: number
Expand Down Expand Up @@ -185,6 +186,7 @@ const topics: any = envVar('WHISPER_TOPICS', 'json')
})

export const env: IEnvironmentConfig = {
hostname: envVar('HOSTNAME'),
apiKey: envVar('API_KEY_SHA256'),
appId: envVar('APP_ID', 'string', true), // Mark with something meaningful to indicate which environment, e.g., attestation-kit_dev_bob
appPort: envVar('PORT', 'int', false, 3000),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,26 @@ export interface IAttestationResult {
certainty?: number
}

export interface IDataRetrievalKit {
dataHostedExternally: boolean
nodeHost: string
attestationDataId: string
passphrase: string
}

export interface IDataRetrievalOther {
dataHostedExternally: boolean
retrievalUrl: string
deletionUrl: string
}

export type AttestationRole = 'attester' | 'requester'

export type IAttestationDataJSONB = IEmailAttestationJSONB | IPhoneAttestationJSONB
export type TAttestationDataJSONB = IEmailAttestationJSONB | IPhoneAttestationJSONB

export type TUnresolvedAttestationData = IDataRetrievalKit | IDataRetrievalOther

export type TMaybeAttestationDataJSONB = TUnresolvedAttestationData | TAttestationDataJSONB

export const AttestationStatusDataType = Sequelize.DataType.ENUM(
Object.keys(AttestationStatus)
Expand Down Expand Up @@ -90,7 +107,7 @@ export default class Attestation extends Sequelize.Model<Attestation> {
get data() {
return this.getDataValue('data')
}
set data(value: IAttestationDataJSONB) {
set data(value: TAttestationDataJSONB) {
this.setDataValue('data', value)
}

Expand Down Expand Up @@ -160,7 +177,8 @@ export default class Attestation extends Sequelize.Model<Attestation> {
)
}

validateJobDetailsView(): IJobDetails {
validateJobDetailsView = (): IJobDetails => {
if (!this.data || !this.data.data) throw new Error('Invalid data')
return {
// Making sure the data prop only contains what the validate job details cares about
data: {
Expand Down
72 changes: 72 additions & 0 deletions app/shared/models/AttestationData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import * as Sequelize from 'sequelize-typescript'
import {Attestation} from '@shared/models'
import {WhisperMsgDataType} from '@shared/models/NegotiationMsg'
import {bufferToHex, sha256} from 'ethereumjs-util'

@Sequelize.Table({tableName: 'attestation_data'})
export default class AttestationData extends Sequelize.Model<AttestationData> {
@Sequelize.Column({
type: Sequelize.DataType.UUID,
allowNull: false,
autoIncrement: false,
primaryKey: true,
})
id: string

@Sequelize.CreatedAt created: Date

@Sequelize.UpdatedAt updated: Date

@Sequelize.Column({
type: Sequelize.DataType.UUID,
allowNull: false,
autoIncrement: false,
primaryKey: true,
})
attestationId: string

@Sequelize.BelongsTo(() => Attestation, {
foreignKey: 'attestationId',
})
Attestation?: Attestation

// Column to specify data storage type
@Sequelize.Column({
allowNull: false,
type: WhisperMsgDataType,
})
messageType: string

// Column to specify data storage type
@Sequelize.Column({
allowNull: false,
type: Sequelize.DataType.STRING,
})
datatype: 'text' | 'blob'

// Column for data stored as text
@Sequelize.Column({
allowNull: false,
type: Sequelize.DataType.TEXT,
})
dtext: string

// Column for data stored as blob
@Sequelize.Column({
allowNull: false,
type: Sequelize.DataType.BLOB,
})
dblob: Buffer

// Cryptographic challenge (SHA256'ed password)
@Sequelize.Column({
allowNull: false,
type: Sequelize.DataType.STRING,
})
challenge: string

testChallenge = (passphrase: string) => {
let passphraseHash = bufferToHex(sha256(passphrase))
return passphrase && this.challenge && passphraseHash === this.challenge
}
}
11 changes: 7 additions & 4 deletions app/shared/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import {Sequelize} from 'sequelize-typescript'
import {env} from '@shared/environment'
import * as config from '../../config/database'
import Negotiation from '@shared/models/Attestations/Negotiation'
import NegotiationMsg from '@shared/models/Attestations/NegotiationMsg'
import WhisperFilters from '@shared/models/Attestations/WhisperFilters'
import Attestation from '@shared/models/Attestations/Attestation'
import Negotiation from '@shared/models/Negotiation'
import NegotiationMsg from '@shared/models/NegotiationMsg'
import WhisperFilters from '@shared/models/WhisperFilters'
import Attestation from '@shared/models/Attestation'
import AttestationData from '@shared/models/AttestationData'
import GasPrice from '@shared/models/GasPrice'
import Ping from '@shared/models/Ping'

Expand All @@ -30,6 +31,7 @@ sequelize.addModels([
NegotiationMsg,
WhisperFilters,
Attestation,
AttestationData,
GasPrice,
Ping,
])
Expand All @@ -43,6 +45,7 @@ export {
sequelize,
WhisperFilters,
Attestation,
AttestationData,
GasPrice,
Ping,
}
13 changes: 3 additions & 10 deletions app/shared/whisper/attesterActions.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
import * as newrelic from 'newrelic'
const uuid = require('uuidv4')
import BigNumber from 'bignumber.js'
import {
handleSolicitation,
handleJobDetails,
} from '@shared/whisper/attesterActions'
import {
ISolicitation,
ISendJobDetails,
EMsgTypes,
} from '@shared/whisper/msgTypes'
import {handleSolicitation, handleJobDetails} from '@shared/whisper/attesterActions'
import {ISolicitation, ISendJobDetails, EMsgTypes} from '@shared/whisper/msgTypes'
import {NegotiationMsg} from '@shared/models'
import {MessageSubscribers} from '@shared/whisper/subscriptionHandler'
import {toBuffer, bufferToHex} from 'ethereumjs-util'
import * as Wallet from 'ethereumjs-wallet'
import {signSessionID, signPaymentAuthorization} from '@shared/ethereum/signingLogic'
import {PersistDataTypes} from '@shared/whisper/persistDataHandler'
import {signAttestationRequest} from '@shared/ethereum/signingLogic'
import {PersistDataTypes} from '@shared/whisper/persistDataHandler'
import {
attesterWallet,
requesterWallet,
Expand Down
Loading