Commit a3f40dd1 authored by James Calfee's avatar James Calfee
Browse files

Adds signature verify to upload

parent a0c37458
#### Configure
## Configure
> cp ./config/env_example.sh env_prod.sh
See also: `./config/index.js`
#### Example upload
## Example upload
> curl -v -F "data=@$HOME/Pictures/blue_red_pill.jpg" http://localhost:3234/image
#### Start the server
> export STEEMIT_UPLOAD_TEST_KEY=true
> npm start
Use the hash from above and verify:
#### Download the test image
> curl -v http://localhost:3234/image/a190c0596a37398427e51bcbee7c94f1007075629828d62005735c6c2d2ffeef|sha256sum
> curl -v http://localhost:3234/image/a190c0596a37398427e51bcbee7c94f1007075629828d62005735c6c2d2ffeef > $HOME/Pictures/blue_red_pill.jpg
#### Upload again (signed by user `steem` using a test key)
> curl -v -F "data=@$HOME/Pictures/blue_red_pill.jpg" http://localhost:3234/image/steem/205d8bcafb9e0e0897e2db330aa2bd1ca4f7764ad9b1ba04a2a9651453aee72f4a685bd631ad60111f8018fd65d3fc7e951c0039476c270e859bb6760836dcb40d
## Create a signature
```
import {PrivateKey, Signature} from 'shared/ecc'
const bufSha = new Buffer('a190c0596a37398427e51bcbee7c94f1007075629828d62005735c6c2d2ffeef', 'hex')
const d = PrivateKey.fromSeed('')
const sig = Signature.signBufferSha256(bufSha, d)
console.log('Signature', sig.toHex())
```
Outputs 205d8bcafb9e0e0897e2db330aa2bd1ca4f7764ad9b1ba04a2a9651453aee72f4a685bd631ad60111f8018fd65d3fc7e951c0039476c270e859bb6760836dcb40d
\ No newline at end of file
import AWS from 'aws-sdk'
import config from 'config'
import {rateLimitReq, missing} from 'app/server/utils'
import Apis from 'shared/api_client/ApiInstances'
import fs from 'fs'
import {hash} from 'shared/ecc'
import {rateLimitReq, missing} from 'app/server/utils'
import {hash, Signature, PublicKey, PrivateKey} from 'shared/ecc'
const testKey = config.testKey ? PrivateKey.fromSeed('').toPublicKey() : null
const {amazonBucket, protocol, host, port} = config
const s3 = new AWS.S3()
......@@ -16,44 +20,79 @@ const koaBody = require('koa-body')({
// formidable: { uploadDir: '/tmp', }
})
router.post('/:type', koaBody, function *() {
router.post('/:type/:username/:signature', koaBody, function *() {
try {
const {files, fields} = this.request.body
if(missing(this, files, 'data')) return
// if(missing(this, fields, 'username')) return
if(missing(this, this.params, 'type')) return
if(missing(this, this.params, 'username')) return
if(missing(this, this.params, 'signature')) return
// const {username} = fields
const {type} = this.params
if(type !== 'image') {
this.status = 404
this.statusText = `Unsupported type ${type}. Try using 'image'`
this.body = {error: this.statusText}
return
}
// Question: How can I keep a multipart form upload in memory (skip the file)?
const {signature} = this.params
const sig = Signature.fromHex(signature)
const {username} = this.params
const [{posting: {key_auths}, weight_threshold}] = yield Apis.db_api('get_accounts', [this.params.username])
const [[posting_pubkey, weight]] = key_auths
if(weight < weight_threshold) {
this.status = 404
this.statusText = `User ${username} has an unsupported posting key configuration.`
this.body = {error: this.statusText}
return
}
const posting = PublicKey.fromString(posting_pubkey)
// How can I keep a multipart form upload in memory (skip the file)?
// https://github.com/tunnckoCore/koa-better-body/issues/67
yield new Promise(resolve => {
fs.readFile(files.data.path, 'binary', (err, data) => {
if(err) return console.error(err)
if(err) {
console.error(err)
this.status = 404
this.statusText = `Upload failed.`
this.body = {error: this.statusText}
resolve()
return
}
fs.unlink(files.data.path)
const dataBuffer = new Buffer(data, 'binary')
const sha = hash.sha256(dataBuffer)
if(!sig.verifyHash(sha, posting) && !(testKey && sig.verifyHash(sha, testKey))) {
this.status = 404
this.statusText = `Signature did not verify.`
this.body = {error: this.statusText}
resolve()
return
}
const key = `${type}/${sha.toString('hex')}`
const params = {Bucket: amazonBucket, Key: key, Body: dataBuffer};
s3.putObject(params, (err, data) => {
if(err) {
console.log(err)
this.status = 404
this.statusText = `Error uploading ${key}.`
resolve()
return
}
console.log(`Uploaded ${amazonBucket}/${key}`);
const url = `${protocol}://${host}:${port}/${key}`
this.body = {files: [{url}]}
const params = {Bucket: amazonBucket, Key: key, Body: dataBuffer};
s3.putObject(params, (err, data) => {
if(err) {
console.log(err)
this.status = 404
this.statusText = `Error uploading ${key}.`
this.body = {error: this.statusText}
resolve()
return
}
console.log(`Uploaded ${amazonBucket}/${key}`);
const url = `${protocol}://${host}:${port}/${key}`
this.body = {files: [{url}]}
resolve()
})
})
})
......
......@@ -3,3 +3,4 @@
export STEEMIT_UPLOAD_AWS_KEY_ID=
export STEEMIT_UPLOAD_AWS_SECRET_KEY=
import AWS from 'aws-sdk'
const toBoolean = s => s == null || s.trim() === '' ? false : JSON.parse(s)
AWS.config.accessKeyId = process.env.STEEMIT_UPLOAD_AWS_KEY_ID
AWS.config.secretAccessKey = process.env.STEEMIT_UPLOAD_AWS_SECRET_KEY
......@@ -9,6 +11,7 @@ export default {
host: process.env.STEEMIT_UPLOAD_HTTP_HOST || 'localhost',
port: process.env.STEEMIT_UPLOAD_HTTP_PORT || 3234,
amazonBucket: process.env.STEEMIT_UPLOAD_AMAZON_BUCKET || "steem-upload-manager-test",
testKey: toBoolean(process.env.STEEMIT_UPLOAD_TEST_KEY)
}
if(!AWS.config.accessKeyId) throw new Error('Missing STEEMIT_UPLOAD_AWS_KEY_ID')
......
......@@ -112,6 +112,11 @@ class Signature {
return this.verifyHash(_hash, public_key);
};
/**
@param {Buffer} sha256 hash
@param {./PublicKey}
@return {boolean}
*/
verifyHash(hash, public_key) {
assert.equal(hash.length, 32, "A SHA 256 should be 32 bytes long, instead got " + hash.length);
return ecdsa.verify(curve, hash, {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment