Skip to content
This repository was archived by the owner on Feb 20, 2019. 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
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"compression": "^1.7.1",
"cors": "^2.8.4",
"dotenv": "^4.0.0",
"eth-sig-util": "^1.4.2",
"ethereumjs-util": "^5.2.0",
"express": "^4.16.2",
"file-type": "^7.7.1",
Expand Down
12 changes: 9 additions & 3 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@ if (dotenvResult.error) {

// this is the message that will be signed by MetaMask and checked against when
// authenticating users
const personalMessageToSign = 'Please sign this message to authenticate with the Codex Title Registry.'
const typedDataToSign = [
{
type: 'string',
name: 'Sign In',
value: 'Please sign this message to authenticate with the Codex Title Registry.',
},
]

const fullConfig = {
development: {

personalMessageToSign,
typedDataToSign,

mongodb: {
dbUris: {
Expand Down Expand Up @@ -55,7 +61,7 @@ const fullConfig = {

staging: {

personalMessageToSign,
typedDataToSign,

mongodb: {
dbUris: {
Expand Down
27 changes: 8 additions & 19 deletions src/routes/auth-token/create.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,20 @@
import Joi from 'joi'
import jwt from 'jsonwebtoken'
import ethUtil from 'ethereumjs-util'
import ethSigUtil from 'eth-sig-util'
import RestifyErrors from 'restify-errors'

import models from '../../models'
import config from '../../config'
import logger from '../../services/logger'

const hashedPersonalMessage = ethUtil.hashPersonalMessage(ethUtil.toBuffer(config.personalMessageToSign))

export default {

method: 'post',
path: '/auth-tokens?',

parameters: Joi.object().keys({

// NOTE: the length of the signedData may change if the ethereumjs-util
// package is ever updated and the fromRpcSignature method changes it's
// length validation, as indicated by a comment in the source
//
// see: https://github.com/ethereumjs/ethereumjs-util/blob/fde15dd/index.js
//
// NOTE: signedData should not have the 0x prefix as Joi will validate it as
// a raw Buffer
signedData: Joi.binary().encoding('hex').length(65).required(),
signedData: Joi.string().required(),

userAddress: Joi.string().regex(/^0x[0-9a-f]{40}$/i, 'ethereum address').lowercase().required(),

Expand All @@ -36,17 +26,16 @@ export default {

handler(request, response) {

// see: https://hackernoon.com/never-use-passwords-again-with-ethereum-and-metamask-b61c7e409f0d
// see: https://medium.com/metamask/scaling-web3-with-signtypeddata-91d6efc8b290

try {

const { v, r, s } = ethUtil.fromRpcSig(ethUtil.toBuffer(request.parameters.signedData))
const publicKey = ethUtil.ecrecover(hashedPersonalMessage, v, r, s)

const userAddressBuffer = ethUtil.toBuffer(request.parameters.userAddress)
const senderAddressBuffer = ethUtil.publicToAddress(publicKey)
const recoveredAddress = ethSigUtil.recoverTypedSignature({
sig: request.parameters.signedData,
data: config.typedDataToSign,
})

if (!senderAddressBuffer.equals(userAddressBuffer)) {
if (recoveredAddress !== request.parameters.userAddress) {
// throw a blank error here since it'll just get picked up by the catch
// below anyway
throw new Error()
Expand Down