Skip to content
This repository has been archived by the owner on Mar 4, 2021. It is now read-only.

Commit

Permalink
Merge branch 'master' into fix/server_settings
Browse files Browse the repository at this point in the history
  • Loading branch information
charly committed Nov 13, 2018
2 parents ab69a64 + 42c84b9 commit c786258
Show file tree
Hide file tree
Showing 16 changed files with 360 additions and 66 deletions.
8 changes: 2 additions & 6 deletions config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
// Private key associated with the service's identity
export const privateIdentityKey = Buffer.from('7A59BC95029803EC082BFEBBA8094F9D6B58AAB1A23B7CA2D9C6B96F21E1A0A4', 'hex')
export const privateIdentityKey = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex')

// Where is your service deployed. E.g. https://demo-sso.jolocom.com
export const serviceUrl = 'http://localhost:9000'
export const serviceUrl = ''

// What credentials do you require during authentication, and associated constraints
export const credentialRequirements = [
{
type: ['Credential', 'ProofOfEmailCredential'],
constraints: [{ '==': [true, true] }]
},
{
type: ['Credential', 'ProofOfNameCredential'],
constraints: [{ '==': [true, true] }]
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@
"body-parser": "^1.18.3",
"connected-react-router": "^4.4.1",
"cors": "^2.8.4",
"cred-types-jolocom-demo": "^0.0.1",
"css-loader": "0.28.7",
"express": "^4.16.3",
"file-loader": "0.11.2",
"form-data": "^2.3.2",
"history": "^4.7.2",
"isomorphic-fetch": "^2.2.1",
"jest": "22.4.2",
"jolocom-lib": "^2.0.10",
"jolocom-lib": "^2.0.12",
"material-ui": "^0.20.2",
"promise": "8.0.1",
"react": "^16.4.2",
Expand All @@ -33,6 +34,7 @@
"redux-actions": "^2.6.1",
"redux-thunk": "^2.3.0",
"resolve": "1.6.0",
"sha3": "^1.2.2",
"socket.io": "^2.1.1",
"socket.io-client": "^2.1.1",
"style-loader": "0.19.0",
Expand Down
135 changes: 126 additions & 9 deletions server/routes.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import * as path from 'path'
import { credentialRequirements } from '../config'
import { credentialRequirements, serviceUrl } from '../config'
import { Express } from 'express'
import { validateCredentialSignatures, extractDataFromClaims } from '../src/utils/'
import { validateCredentialSignatures, extractDataFromClaims, randomString } from '../src/utils/'
import { RedisApi } from './types'
import { JSONWebToken } from 'jolocom-lib/js/interactionFlows/JSONWebToken';
import { CredentialRequest } from 'jolocom-lib/js/interactionFlows/credentialRequest/credentialRequest';
import { JSONWebToken } from 'jolocom-lib/js/interactionFlows/JSONWebToken'
import { CredentialRequest } from 'jolocom-lib/js/interactionFlows/credentialRequest/credentialRequest'
import { InteractionType } from 'jolocom-lib/js/interactionFlows/types'
import { IdentityWallet } from 'jolocom-lib/js/identityWallet/identityWallet'
import { JolocomLib } from 'jolocom-lib'
const SHA3 = require('sha3')

export const configureRoutes = async (app: Express, redisApi: RedisApi) => {

const { setAsync } = redisApi
export const configureRoutes = async (app: Express, redisApi: RedisApi, iw: IdentityWallet) => {
const { setAsync, getAsync } = redisApi

app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '../dist/index.html'))
Expand All @@ -19,13 +22,126 @@ export const configureRoutes = async (app: Express, redisApi: RedisApi) => {
res.sendFile(path.join(__dirname, `../dist/img/${name}`))
})

app.get('/authentication/credentialRequest', async (req, res) => {
const userId = randomString(5)
const callbackURL = `${serviceUrl}/authentication/${userId}`

const credentialRequest = await iw.create
.credentialRequestJSONWebToken({
typ: InteractionType.CredentialRequest,
credentialRequest: {
callbackURL,
credentialRequirements
}
})
.encode()

res.json({ token: credentialRequest })
})

app.get('/credentialoffer', async(req, res) => {
const challenge = randomString(5)

await redisApi.setAsync(challenge, 'true')

const credOffer = await iw.create.credentialOfferRequestJSONWebToken({
typ: InteractionType.CredentialOfferRequest,
credentialOffer: {
instant: true,
challenge: challenge,
requestedInput: {},
callbackURL: `${serviceUrl}/receive/`
}
})

res.json({ token: credOffer.encode() })
})

app.get('/credentialRequest', async (req, res) => {
const credentialRequest = await iw.create.credentialRequestJSONWebToken({
typ: InteractionType.CredentialRequest,
credentialRequest: {
callbackURL: 'demosso://authenticate/',
credentialRequirements
}
})
const jwtCR = credentialRequest.encode()
res.send(jwtCR)
})

app.post('/receive', async (req, res) => {
const { token } = req.body

// Validates the signature on the JWT
const credentialOfferReq = await JolocomLib.parse.interactionJSONWebToken.decode(token)
const did = credentialOfferReq.iss.substring(0, credentialOfferReq.iss.indexOf('#'))

const didHash = SHA3.SHA3Hash()
didHash.update(did)

const challenge = await getAsync(`ch:${didHash.digest('hex')}`)
const backup = await getAsync(credentialOfferReq.credentialOffer.challenge)

console.log(credentialOfferReq)
if (credentialOfferReq.credentialOffer.challenge !== challenge && !backup) {
res.status(401).send('incorrect challenge string')
return
}

const tinkererToken = await iw.create.signedCredential({
metadata: {
type: ['Credential', 'ProofOfTinkererCredential'],
name: 'Tinkerer',
context: [
{
ProofOfTinkererCredential: 'https://identity.jolocom.com/terms/ProofOfTinkererCredential'
}
]
},
claim: {
note: 'Thank you for attending our session at Web3!'
},
// Handle this on the library side, provide both the key id, and the issuer's did.
subject: credentialOfferReq.iss.substring(0, credentialOfferReq.iss.indexOf('#'))
})

const encodedCredential = await iw.create
.credentialsReceiveJSONWebToken({
iss: iw.getIdentity().getDID(),
typ: InteractionType.CredentialsReceive,
credentialsReceive: {
signedCredentials: [tinkererToken.toJSON()]
}
})
.encode()

res.json({ token: encodedCredential })
})

app.post('/receiveCredential', async (req, res) => {
const userId = randomString(5)
const callbackURL = `${serviceUrl}/authentication/${userId}`

const credentialRequest = await iw.create
.credentialRequestJSONWebToken({
typ: InteractionType.CredentialRequest,
credentialRequest: {
callbackURL,
credentialRequirements
}
})
.encode()

res.json({ token: credentialRequest })
})

app.post('/authentication/:clientId', async (req, res, next) => {
const { clientId } = req.params
const { token } = req.body

console.log(token)
try {
const { credentialResponse } = await JSONWebToken.decode(token)
const { credentialResponse, iss } = await JSONWebToken.decode(token)
await validateCredentialSignatures(credentialResponse)

const credentialRequest = CredentialRequest.create({
Expand All @@ -37,9 +153,10 @@ export const configureRoutes = async (app: Express, redisApi: RedisApi) => {
throw new Error('The supplied credentials do not match the types of the requested credentials')
}

// KeyId -> Issuer DID conversion should be abstracted.
const userData = {
...extractDataFromClaims(credentialResponse),
did: credentialResponse.issuer,
did: iss.substring(0, iss.indexOf('#')),
status: 'success'
}

Expand Down
4 changes: 2 additions & 2 deletions server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ app.use(cors())
const { getAsync, setAsync, delAsync } = configureRedisClient()
const registry = JolocomLib.registry.jolocom.create()

configureRoutes(app, {setAsync, getAsync, delAsync})

registry.authenticate(privateIdentityKey).then(identityWallet => {
configureRoutes(app, {setAsync, getAsync, delAsync}, identityWallet)
configureSockets(server, identityWallet, new DbWatcher(getAsync), {getAsync, setAsync, delAsync})
configureRoutes(app, {setAsync, getAsync, delAsync}, identityWallet)
})

server.listen(9000, () => {
Expand Down
28 changes: 28 additions & 0 deletions server/sockets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { DbWatcher } from './dbWatcher'
import { IdentityWallet } from 'jolocom-lib/js/identityWallet/identityWallet'
import { RedisApi } from './types'
import { InteractionType } from 'jolocom-lib/js/interactionFlows/types'
import { randomString } from '../src/utils';
const SHA3 = require('sha3')

export const configureSockets = (
server: http.Server,
Expand All @@ -18,8 +20,34 @@ export const configureSockets = (
const baseSocket = io(server).origins('*:*')

const qrCodeSocket = baseSocket.of('/qr-code')
const qrCodeReceive = baseSocket.of('/qr-receive')
const dataSocket = baseSocket.of('/sso-status')

qrCodeReceive.on('connection', async socket => {
const { did, answer } = socket.handshake.query

const didHash = SHA3.SHA3Hash()
didHash.update(did)

const challenge = randomString(5)

await redisApi.setAsync(`ch:${didHash.digest('hex')}`, challenge)
await redisApi.setAsync(`ans:${didHash.digest('hex')}`, answer)

const credOffer = await identityWallet.create.credentialOfferRequestJSONWebToken({
typ: InteractionType.CredentialOfferRequest,
credentialOffer: {
instant: true,
challenge: challenge,
requestedInput: {},
callbackURL: `${serviceUrl}/receive/`
}
})

const qrCode = await new SSO().JWTtoQR(credOffer.encode())
socket.emit(did, qrCode)
})

qrCodeSocket.on('connection', async socket => {
const { userId } = socket.handshake.query

Expand Down
1 change: 1 addition & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ ReactDOM.render(
<ConnectedRouter history={history}>
<MuiThemeProvider theme={theme}>
<Switch>
{/* <Route exact path="/" component={Dashboard} /> */}
<Route exact path="/" component={Landing} />
<Route path="/dashboard" component={Dashboard} />
</Switch>
Expand Down
35 changes: 27 additions & 8 deletions src/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { loginProviders } from '../reducers'
import io from 'socket.io-client'
import { push } from 'connected-react-router'
import { serviceUrl } from '../../config'
import { UserData } from '../ui/containers/types';
import { UserData } from '../ui/containers/types'
import { randomString } from '../utils'

export const showDialog = (providerName: loginProviders) => {
return {
Expand Down Expand Up @@ -31,6 +32,13 @@ export const setUserData = (data: UserData) => {
}
}

export const setReceivedQr = (encodedImage: string) => {
return {
type: 'QR_RECEIVE_SET',
value: encodedImage
}
}

export const initiateLogin = (loginProvider: loginProviders) => {
return async (dispatch: Function) => {
if (loginProvider !== loginProviders.jolocom) {
Expand All @@ -44,12 +52,29 @@ export const initiateLogin = (loginProvider: loginProviders) => {
dispatch(showDialog(loginProvider))

const data = await awaitUserData(randomId)
const parsed = JSON.parse(data)

dispatch(setUserData(JSON.parse(data)))
dispatch(setQRCode(undefined))
dispatch(setUserData(parsed))
dispatch(push('/dashboard'))
}
}

export const initiateReceiving = (did: string, answer: string) => {
return async (dispatch: Function) => {
const qrCode = await getOfferQrCode(did, answer)
dispatch(setReceivedQr(qrCode))
}
}

const getOfferQrCode = async (did: string, answer: string): Promise<string> => {
const socket = io(`${serviceUrl}/qr-receive`, { query: { did, answer} })
return new Promise<string>(resolve => {
socket.on(did, (qrCode: string) => resolve(qrCode))
})
}


const getQrCode = async (randomId: string): Promise<string> => {
const socket = io(`${serviceUrl}/qr-code`, { query: { userId: randomId } })
return new Promise<string>(resolve => {
Expand All @@ -65,10 +90,4 @@ export const awaitUserData = async (randomId: string): Promise<string> => {
return new Promise<string>(resolve => {
socket.on(randomId, (data: string) => resolve(data))
})
}

const randomString = (length: number) => {
return Math.random()
.toString(36)
.substr(2, length)
}
6 changes: 5 additions & 1 deletion src/reducers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface DefaultState {
dialog: {
loginProvider: loginProviders
qrCode: string
qrReceiveCode: string
}
userData: {
did: string
Expand All @@ -21,7 +22,8 @@ export interface DefaultState {
export const defaultState: DefaultState = {
dialog: {
loginProvider: loginProviders.none,
qrCode: ''
qrCode: '',
qrReceiveCode: ''
},
userData: {
did: '',
Expand All @@ -43,6 +45,8 @@ export function rootReducer(state = defaultState, action: any) {
return {...state, dialog: { ...state.dialog, loginProvider: loginProviders.none }}
case 'QR_CODE_SET':
return {...state, dialog: { ...state.dialog, qrCode: action.value}}
case 'QR_RECEIVE_SET':
return {...state, dialog: { ...state.dialog, qrReceiveCode: action.value}}
default:
return state
}
Expand Down
Loading

0 comments on commit c786258

Please sign in to comment.