Skip to content

Commit c42a57b

Browse files
committed
Merge branch 'master' of github.com:kyledrake/coinpunk
2 parents 0a037dd + f607866 commit c42a57b

File tree

10 files changed

+255
-91
lines changed

10 files changed

+255
-91
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ public/config.json
44
coinpunk.key
55
coinpunk.csr
66
coinpunk.crt
7+
*.swp

docs/INSTALL.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,18 @@ node start.js
156156
```
157157

158158

159-
Try to connect by going to http://YOURADDRESS.COM:8080 (If your useing the SSL config then try http://YOURADDRESS.COM:8085. OR https://YOURADDRESS.COM:8086) If it loads, then you should be ready to use Coinpunk!
159+
Try to connect by going to http://YOURADDRESS.COM:8080 (If you're using the SSL config then try http://YOURADDRESS.COM:8085. OR https://YOURADDRESS.COM:8086) If it loads, then you should be ready to use Coinpunk!
160160

161161
## Backing up Database
162162

163163
Redis maintains a file called `/var/lib/redis/dump.rdb`, which is a backup of your Redis database. It is safe to copy this file while Redis is running. **It is strongly recommended that you backup this file frequently.** You can also setup a Redis slave to listen to master in real time. Ideally you should do both!
164+
165+
## Extra Steps for Contributors
166+
167+
If you want to contribute code to this project, you will need to install Grunt. Grunt is a task-runner that presently handles minifying and uglifying Coinpunk's CSS and JS resources. To install Grunt:
168+
169+
```
170+
sudo npm install -g grunt-cli
171+
```
172+
173+
Once that's done, running `grunt` in your Coinpunk directory will minify and uglify everything, and running `grunt watch` will automatically uglify your JS files when they change.

lib/coinpunk/server.js

+141-40
Original file line numberDiff line numberDiff line change
@@ -72,33 +72,46 @@ server.get('/api/generateAuthKey', function(req, res) {
7272
server.post('/api/setAuthKey', function(req, res) {
7373
var code = speakeasy.time({key: req.body.key, encoding: 'base32'});
7474

75-
if(code != req.body.code)
75+
if(code != req.body.code) {
7676
return res.send({set: false});
77+
}
7778

78-
db.setAuthKey(req.body.serverKey, req.body.key, function(err, success) {
79-
if(err)
79+
db.sessionKeyValid(req.body.serverKey, req.body.sessionKey, function(err, success) {
80+
if(err || success == false) {
8081
return res.send({set: false});
81-
res.send({set: true});
82+
}
83+
84+
db.setAuthKey(req.body.serverKey, req.body.key, function(err, success) {
85+
if(err) {
86+
return res.send({set: false});
87+
}
88+
res.send({set: true});
89+
});
8290
});
8391
});
8492

8593
server.post('/api/disableAuthKey', function(req, res) {
86-
db.getWalletRecord(req.body.serverKey, function(err, payload) {
87-
if(err)
88-
console.log('Wallet Get Error: '+err);
94+
db.sessionKeyValid(req.body.serverKey, req.body.sessionKey, function(err, success) {
95+
if(err || success == false)
96+
return res.send({result: 'error', message: 'session key was invalid'});
8997

90-
if(!payload || !payload.authKey)
91-
return res.send({result: 'error', message: 'no auth key found for this wallet'});
98+
db.getWalletRecord(req.body.serverKey, function(err, payload) {
99+
if(err)
100+
console.log('Wallet Get Error: '+err);
101+
102+
if(!payload || !payload.authKey)
103+
return res.send({result: 'error', message: 'no auth key found for this wallet'});
92104

93-
var code = speakeasy.time({key: payload.authKey, encoding: 'base32'});
105+
var code = speakeasy.time({key: payload.authKey, encoding: 'base32'});
94106

95-
if(code != req.body.authCode)
96-
return res.send({result: 'error', message: 'invalid auth code'});
107+
if(code != req.body.authCode)
108+
return res.send({result: 'error', message: 'invalid auth code'});
97109

98-
db.disableAuthKey(req.body.serverKey, function(err, result) {
99-
if(err)
100-
return res.send({result: 'error', message: 'could not update database, please try again later'});
101-
res.send({result: 'success'});
110+
db.disableAuthKey(req.body.serverKey, function(err, result) {
111+
if(err)
112+
return res.send({result: 'error', message: 'could not update database, please try again later'});
113+
res.send({result: 'success'});
114+
});
102115
});
103116
});
104117
});
@@ -122,29 +135,47 @@ server.get('/api/wallet', function(req,res) {
122135
return res.send({result: 'error', message: 'Two factor authentication code was invalid'});
123136
}
124137

125-
return res.send({wallet: payload.wallet});
138+
db.generateSessionKey(req.query.serverKey, function(err, key) {
139+
if(err)
140+
return res.send({result: 'error', message: 'Error generating session key, please try again later'});
141+
res.send({wallet: payload.wallet, sessionKey: key});
142+
});
126143
});
127144
});
128145

129146
server.post('/api/wallet/delete', function(req, res) {
130-
db.delete(req.body.serverKey, function(err, deleted) {
131-
if(deleted == true)
132-
res.send({result: 'success'});
133-
else
147+
db.sessionKeyValid(req.body.serverKey, req.body.sessionKey, function(isValid) {
148+
if(isValid == false)
149+
return res.send({result: 'error', message: 'session key was invalid'});
150+
151+
db.delete(req.body.serverKey, function(err, deleted) {
152+
if(deleted == true)
153+
return res.send({result: 'success'});
134154
res.send({result: 'notfound'});
155+
});
135156
});
136157
});
137158

138159
function saveWallet(req, res) {
160+
if(req.body.sessionKey)
161+
req.body.payload.sessionKey = req.body.sessionKey;
162+
139163
db.set(req.body.serverKey, req.body.payload, function(err, data) {
140164
if(err) {
141165
if(err == 'outOfSync') {
142166
return res.send({result: 'outOfSync', wallet: data.wallet});
143167
} else {
144-
return res.send(errorMessage("Database error: "+JSON.stringify(err)));
168+
return res.send({result: 'error', messages: JSON.stringify(err)});
145169
}
146170
} else {
147-
res.send({result: 'ok'});
171+
if(!req.body.override) {
172+
db.generateSessionKey(req.body.serverKey, function(err, key) {
173+
res.send({result: 'ok', sessionKey: key});
174+
});
175+
return;
176+
} else {
177+
res.send({result: 'ok'});
178+
}
148179
}
149180
});
150181
};
@@ -167,18 +198,10 @@ function saveWalletAndAddresses(req, res) {
167198
bitcoind.batch(batch, function(err, btcres) {});
168199

169200
saveWallet(req, res);
170-
/*
171-
bitcoind.batch(batch, function(err, btcres) {
172-
if(err)
173-
return btcres.send({messages: [err.message]});
174-
175-
saveWallet(req, res);
176-
});
177-
*/
178201
} else {
179202
saveWallet(req, res);
180203
}
181-
}
204+
};
182205

183206
function registerAddresses(addresses, callback) {
184207
var isNew = false;
@@ -202,28 +225,106 @@ function errorResponse(errors) {
202225
return {messages: errors};
203226
}
204227

228+
server.post('/api/change', function(req, res) {
229+
if(!req.body.originalServerKey)
230+
return res.send({result: 'error', message: 'originalServerKey required'});
231+
232+
if(!req.body.serverKey)
233+
return res.send({result: 'error', message: 'serverKey required'});
234+
235+
if(req.body.originalServerKey == req.body.serverKey)
236+
return res.send({result: 'ok'});
237+
238+
db.sessionKeyValid(req.body.originalServerKey, req.body.sessionKey, sessionValidate);
239+
240+
function sessionValidate(err, isValid) {
241+
if(err)
242+
return res.send({result: 'error', message: 'error validating record'});
243+
244+
if(isValid == false)
245+
return res.send({result: 'error', message: 'session was invalid'});
246+
247+
// Check for existing record
248+
db.getWalletRecord(req.body.serverKey, existingWalletRecord);
249+
};
250+
251+
function existingWalletRecord(err, existingRecord) {
252+
if(err || existingRecord)
253+
return res.send({result: 'error', message: 'cannot change'});
254+
255+
db.getWalletRecord(req.body.originalServerKey, walletRecord);
256+
};
257+
258+
function walletRecord(err, record) {
259+
if(err)
260+
return res.send({result: 'error', message: 'error getting originalServerKey record, please try again later'});
261+
262+
if(!record)
263+
return res.send({result: 'error', message: 'could not find originalServerKey record'});
264+
265+
if(record.sessionKey && record.sessionKey != req.body.sessionKey)
266+
return res.send({result: 'error', message: 'invalid sessionKey'});
267+
268+
var newRecord = {
269+
sessionKey: record.sessionKey,
270+
email: (req.body.email || record.email),
271+
payloadHash: req.body.payloadHash,
272+
wallet: req.body.wallet
273+
};
274+
275+
if(record.authKey)
276+
newRecord.authKey = record.authKey;
277+
278+
db.set(req.body.serverKey, newRecord, recordSaved);
279+
};
280+
281+
function recordSaved(err, result) {
282+
if(err)
283+
return res.send({result: 'error', message: 'error changing record, please try again later'});
284+
285+
db.delete(req.body.originalServerKey, oldRecordDeleted);
286+
};
287+
288+
function oldRecordDeleted(err, isDeleted) {
289+
if(err)
290+
return res.send({result: 'error', message: 'error changing record, please try again later'});
291+
292+
res.send({result: 'ok'});
293+
};
294+
});
295+
205296
server.post('/api/wallet', function(req,res) {
206-
db.getWallet(req.body.serverKey, function(err, wallet) {
297+
db.getWalletRecord(req.body.serverKey, function(err, record) {
207298
if(err) {
208299
console.log('Database error: '+err);
209300
return res.send(errorResponse('There was a server error, please try again later.'));
210301
}
211302

212303
// New wallet
213304
if(!req.body.override) {
214-
if(wallet)
215-
return res.send({result: 'exists', wallet: wallet});
305+
if(record && record.wallet)
306+
return res.send({result: 'exists'});
216307

217-
if(req.body.payload.email != undefined)
308+
if(req.body.payload.email != undefined) {
218309
db.checkEmailExists(req.body.payload.email, function(err, response) {
219310
if(response == true)
220311
return res.send({result: 'error', messages: ['Email address already exists']});
221-
else
222-
return saveWalletAndAddresses(req, res);
312+
saveWalletAndAddresses(req, res);
223313
});
224-
}
314+
}
225315

226-
return saveWalletAndAddresses(req, res);
316+
saveWalletAndAddresses(req, res);
317+
} else {
318+
// Not new, check the session key
319+
db.sessionKeyValid(req.body.serverKey, req.body.sessionKey, function(err, isValid) {
320+
if(err)
321+
return res.send({result: 'error', messages: ['Database error, please try again later']});
322+
if(isValid == false)
323+
return res.send({result: 'error', messages: ['Invalid session key']});
324+
325+
saveWalletAndAddresses(req, res);
326+
});
327+
}
227328
});
228329
});
229330

lib/coinpunk/server/db/redis.js

+34-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var DB = require('../db');
2+
var crypto = require('crypto');
23

34
if(process.env.NODE_ENV == 'test')
45
var redis = require('redis-mock');
@@ -26,8 +27,36 @@ DB.prototype = {
2627
});
2728
},
2829

30+
sessionKeyValid: function(serverKey, sessionKey, callback) {
31+
this.getSessionKey(serverKey, function(err, dbKey) {
32+
if(dbKey && sessionKey == dbKey)
33+
return callback(undefined, true);
34+
callback(undefined, false);
35+
});
36+
},
37+
38+
getSessionKey: function(serverKey, callback) {
39+
this.redis.hget(serverKey, 'sessionKey', function(err, res) {
40+
if(err)
41+
return callback(err);
42+
callback(undefined, res);
43+
});
44+
},
45+
46+
generateSessionKey: function(serverKey, callback) {
47+
var self = this;
48+
crypto.randomBytes(24, function(ex, buf) {
49+
var token = buf.toString('hex');
50+
self.redis.hset(serverKey, 'sessionKey', token, function(err, res) {
51+
if(err)
52+
return callback(err);
53+
callback(undefined, token);
54+
});
55+
});
56+
},
57+
2958
setAuthKey: function(serverKey, authKey, callback) {
30-
this.redis.hmset(serverKey, 'authKey', authKey, function(err, res) {
59+
this.redis.hset(serverKey, 'authKey', authKey, function(err, res) {
3160
if(err)
3261
return callback(err);
3362
callback(undefined, true);
@@ -77,28 +106,28 @@ DB.prototype = {
77106
self.redis.hmset(serverKey, payload, callback);
78107
}
79108
});
80-
109+
81110
},
82111

83112
delete: function(serverKey, callback) {
84113
this.redis.del(serverKey, function(err, res) {
85114
if(err)
86115
callback(err);
87-
116+
88117
if(res == 1)
89118
callback(undefined, true);
90119
else
91120
callback(undefined, false);
92121
});
93122
},
94-
123+
95124
checkEmailExists: function(email, callback) {
96125
var email = email.toString().toLowerCase();
97126
var self = this;
98127
this.redis.keys('*', function(err, serverKeys) {
99128
if(err)
100129
return callback(err);
101-
130+
102131
for(var k=0;k<serverKeys.length;k++)
103132
self.redis.hmget(serverKeys[k], 'email', function(err, res) {
104133
if(err)

public/js/all.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/js/coinpunk/controller.js

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ coinpunk.Controller.prototype.saveWallet = function(data, callback) {
3232
var data = data || {};
3333
data.serverKey = coinpunk.wallet.serverKey;
3434

35+
if(coinpunk.wallet.sessionKey)
36+
data.sessionKey = coinpunk.wallet.sessionKey;
37+
3538
if(!data.payload)
3639
data.payload = {};
3740

0 commit comments

Comments
 (0)