aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app.js321
-rw-r--r--package.json29
-rw-r--r--src/app.coffee151
-rw-r--r--src/bcoin.coffee87
-rw-r--r--src/components/SignUp.vue39
-rw-r--r--src/install.coffee16
-rw-r--r--src/main.js9
-rw-r--r--src/passport.coffee35
-rw-r--r--src/redis.coffee7
-rw-r--r--src/routes/sessions.coffee25
-rw-r--r--src/routes/transactions.coffee105
-rw-r--r--src/routes/users.coffee31
-rw-r--r--static/js/calculator.coffee268
-rw-r--r--static/js/generate_address.coffee74
-rw-r--r--static/js/index.coffee44
-rw-r--r--static/js/profile.coffee30
-rw-r--r--static/js/register.coffee53
-rw-r--r--static/js/setup.coffee65
-rw-r--r--static/js/setup.js4
-rw-r--r--static/js/signin.coffee6
-rw-r--r--static/js/wallet.coffee456
21 files changed, 229 insertions, 1626 deletions
diff --git a/app.js b/app.js
index 0703d01f..260fa207 100644
--- a/app.js
+++ b/app.js
@@ -1,193 +1,186 @@
(function() {
- var app, config, engines, express, fetchRates, fs, path, request, route, routes, view, _fn;
+ const indexOf = [].indexOf ||
+ function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i } return -1 }
- fs = require('fs');
+ const request = require('request')
+ const express = require('express')
+ const bodyParser = require('body-parser')
+ const cookieParser = require('cookie-parser')
+ const path = require('path')
+ const passport = require('./passport')
+ const config = require('./config')
+ const fs = require('fs')
+ const proxyMiddleware = require('http-proxy-middleware')
+ const sessions = require("./routes/sessions")(passport)
+ const transactions = require("./routes/transactions")
+ const twilio = require('twilio')
+ const users = require("./routes/users")(sessions)
+ const session = require('express-session')
+ const RedisStore = require('connect-redis')(session)
- express = require('express');
+ sessionStore = new RedisStore(require('./redis').host, {
+ ttl: 172800
+ })
- path = require('path');
+ proxyContext = '/blockcypher'
- engines = require('consolidate');
+ proxyOptions = {
+ target: 'https://api.blockcypher.com',
+ changeOrigin: true,
+ pathRewrite: {
+ '^/blockcypher/': '/'
+ },
+ onProxyReq: function(proxyReq, req, res) {
+ var symbol
+ symbol = indexOf.call(proxyReq.path, '?') >= 0 ? '&' : '?'
+ return proxyReq.path += symbol + "token=" + config.blockcypher_token
+ }
+ }
- request = require('request');
+ proxy = proxyMiddleware(proxyContext, proxyOptions)
- config = require('./config');
+ app = express()
+ app.enable('trust proxy')
+ app.engine('html', require('hogan-express'))
+ app.set('view engine', 'html')
+ app.set('views', __dirname + '/views')
+ app.use(express["static"](__dirname + '/public'))
+ app.use(proxy)
- app = express();
+ app.use(bodyParser.urlencoded({
+ extended: true
+ }))
- app.enable('trust proxy');
+ app.use(bodyParser.json())
- app.engine('html', require('mmm').__express);
+ app.use(bodyParser.json({
+ type: 'application/vnd.api+json'
+ }))
- app.set('view engine', 'html');
+ app.use(cookieParser(config.secret))
- app.set('views', __dirname + '/views');
+ app.use(session({
+ resave: true,
+ saveUninitialized: true,
+ secret: config.secret,
+ store: sessionStore,
+ cookie: {
+ maxAge: 1209600000
+ },
+ key: 'coinos.sid'
+ }))
- app.use(express["static"](__dirname + '/public'));
+ app.use(passport.initialize())
- app.use(express.bodyParser());
+ app.use(passport.session())
- app.use(express.cookieParser());
+ const authorize = function(req, res, next) {
+ var ref, ref1
+ if (req.params.user === ((ref = req.user) != null ? ref.username : void 0) || ((ref1 = req.user) != null ? ref1.username : void 0) === 'admin') {
+ return next()
+ }
+ req.session.redirect = req.path
+ return res.redirect('/login')
+ }
- app.use(app.router);
+ const cache = function(req, res, next) {
+ if (req.path !== '/login') {
+ res.setHeader("Cache-Control", "public, max-age=900")
+ }
+ return next()
+ }
+ let fetchRates
(fetchRates = function() {
request("https://api.bitcoinaverage.com/exchanges/all", function(error, response, body) {
- var file, stream;
try {
- require('util').isDate(JSON.parse(body).timestamp);
- file = 'public/js/rates.json';
- stream = fs.createWriteStream(file);
- return fs.truncate(file, 0, function() {
- return stream.write(body);
- });
- } catch (_error) {}
- });
- return setTimeout(fetchRates, 120000);
- })();
+ require('util').isDate(JSON.parse(body).timestamp)
+ app.set('rates', body)
+ } catch (undefined) {}
+ })
+ return setTimeout(fetchRates, 120000)
+ })()
- routes = {
- '/': 'index',
- '/about': 'about',
- '/coinfest': 'coinfest',
- '/coinos': 'coinos',
- '/contact': 'contact',
- '/directors': 'directors',
- '/membership': 'membership',
- '/merchants': 'merchants',
- '/partners': 'partners',
- '/register': 'register'
- };
+ require('./bcoin').init(app)
- _fn = function(route, view) {
- return app.get(route, function(req, res) {
- return res.render(view, {
- js: (function() {
- return global.js;
- }),
- css: (function() {
- return global.css;
- }),
- layout: 'layout'
- });
- });
- };
- for (route in routes) {
- view = routes[route];
- _fn(route, view);
- }
+ app.get('/', cache, sessions["new"])
- app.get('/users', function(req, res) {
- var db;
- db = require('./redis');
- return db.keys('member:*', function(err, keys) {
- var i, key, users, _i, _len, _results;
- users = [];
- _results = [];
- for (i = _i = 0, _len = keys.length; _i < _len; i = ++_i) {
- key = keys[i];
- _results.push((function(i, db) {
- return db.hgetall(key, function(err, user) {
- if (!user["private"]) {
- users.push(user);
- }
- if (i >= keys.length - 1) {
- users.sort(function(a, b) {
- if (parseInt(a.number) < parseInt(b.number)) {
- return -1;
- }
- if (parseInt(a.number) > parseInt(b.number)) {
- return 1;
- }
- return 0;
- });
- res.write(JSON.stringify(users));
- return res.end();
- }
- });
- })(i, db));
- }
- return _results;
- });
- });
+ app.get('/address', cache, function(req, res) {
+ return res.render('address', {
+ layout: 'layout',
+ js: (function() {
+ return global.js
+ }),
+ css: (function() {
+ return global.css
+ })
+ })
+ })
- app.post('/users', function(req, res) {
- var db, userkey;
- db = require('./redis');
- userkey = "member:" + req.body.email;
- return db.hgetall(userkey, function(err, obj) {
- if (obj) {
- res.status(500).send("Sorry, that email address is already registered");
- return;
- }
- db.sadd("users", userkey);
- return db.incr('members', function(err, number) {
- return db.hmset(userkey, {
- name: req.body.name,
- email: req.body.email,
- address: req.body.address,
- number: number,
- date: req.body.date,
- txid: req.body.txid
- }, function(err, obj) {
- var email;
- if (true || process.env.NODE_ENV === 'production') {
- email = req.body.email;
- res.render('welcome', {
- layout: 'mail',
- js: (function() {
- return global.js;
- }),
- css: (function() {
- return global.css;
- })
- }, function(err, html) {
- var sendgrid;
- sendgrid = require('sendgrid')(config.sendgrid_user, config.sendgrid_password);
- email = new sendgrid.Email({
- to: email,
- subject: 'Welcome to the Co-op!',
- html: html
- });
- return sendgrid.send(email);
- });
- }
- return res.end();
- });
- });
- });
- });
+ app.get('/rates', cache, function(req, res) {
+ res.write(app.get('rates'))
+ })
- app.get('/ticker', function(req, res) {
- var fd;
- fs = require('fs');
- return fd = fs.readFile("./public/js/rates.json", function(err, data) {
- var e, exchange, _base, _base1, _base2;
- (_base = req.query).currency || (_base.currency = 'CAD');
- (_base1 = req.query).symbol || (_base1.symbol = 'quadrigacx');
- (_base2 = req.query).type || (_base2.type = 'bid');
- try {
- exchange = JSON.parse(data)[req.query.currency][req.query.symbol]['rates'][req.query.type].toString();
- } catch (_error) {
- e = _error;
- exchange = "0";
- }
- res.writeHead(200, {
- 'Content-Length': exchange.length,
- 'Content-Type': 'text/plain'
- });
- res.write(exchange);
- return res.end();
- });
- });
+ app.get('/ticker', cache, function(req, res) {
+ fs = require('fs')
+ var base, base1, base2, e, error1, exchange
+ (base = req.query).currency || (base.currency = 'CAD')
+ (base1 = req.query).symbol || (base1.symbol = 'quadrigacx')
+ (base2 = req.query).type || (base2.type = 'bid')
+ try {
+ exchange = JSON.parse(app.get('rates'))[req.query.currency][req.query.symbol]['rates'][req.query.type].toString()
+ } catch (error1) {
+ e = error1
+ exchange = "0"
+ }
+ res.writeHead(200, {
+ 'Content-Length': exchange.length,
+ 'Content-Type': 'text/plain'
+ })
+ res.write(exchange)
+ return res.end()
+ })
+
+ app.get('/tips', cache, function(req, res) {
+ return res.render('tips', {
+ notice: true,
+ layout: 'layout',
+ js: (function() {
+ return global.js
+ }),
+ css: (function() {
+ return global.css
+ })
+ })
+ })
+
+ app.get('/login', cache, sessions["new"])
+ app.post('/login', sessions.create)
+ app.get('/logout', sessions.destroy)
+ app.get('/users.json', users.index)
+ app.get('/register', cache, users["new"])
+ app.get('/users/new', cache, users["new"])
+ app.post('/users', users.create)
+ app.get('/verify/:token', users.verify)
+ app.post('/:user', authorize, users.update)
+ app.get('/:user/edit', authorize, users.edit)
+ app.get('/:user/profile', authorize, users.profile)
+ app.get('/:user/wallet', authorize, users.wallet)
+ app.get('/:user/transactions.json', authorize, transactions.json)
+ app.post('/:user/transactions', transactions.create)
+ app.post('/transactions/:txid', transactions.update)
+ app["delete"]('/:user/transactions/:txid', transactions["delete"])
+ app.get('/:user/report', authorize, transactions.index)
+ app.get('/:user.json', users.json)
+ app.get('/:user', cache, users.show)
app.use(function(err, req, res, next) {
- res.status(500);
- console.log(err);
- return res.end();
- });
+ res.status(500)
+ res.send('An error occurred')
+ console.error(err.stack)
+ return res.end()
+ })
- app.listen(3002);
+ app.listen(3000)
-}).call(this);
+}).call(this)
diff --git a/package.json b/package.json
index 2be452f9..4e3be1d5 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"redis": "^2.6.3",
"slick-carousel": "^1.6.0",
"vue": "^2.1.0",
+ "vue-resource": "^1.0.3",
"vue-router": "^2.1.1"
},
"devDependencies": {
@@ -31,7 +32,6 @@
"chai": "^3.5.0",
"chalk": "^1.1.3",
"chromedriver": "^2.21.2",
- "coffee-loader": "^0.7.2",
"connect-history-api-fallback": "^1.1.0",
"cross-spawn": "^4.0.2",
"css-loader": "^0.25.0",
@@ -84,7 +84,32 @@
"webpack": "^1.13.2",
"webpack-dev-middleware": "^1.8.3",
"webpack-hot-middleware": "^2.12.2",
- "webpack-merge": "^0.14.1"
+ "webpack-merge": "^0.14.1",
+ "async": "2.1.1",
+ "bcoin": "git+https://github.com/bcoin-org/bcoin.git#master",
+ "bcryptjs": "^2.3.0",
+ "bip39": "^2.2.0",
+ "bitcoinjs-lib": "^2.3.0",
+ "bluebird": "^3.4.6",
+ "body-parser": "^1.5.0",
+ "browser-sync": "^2.11.0",
+ "connect-assets": "*",
+ "connect-redis": "3.1.0",
+ "consolidate": "0.14.1",
+ "cookie-parser": "^1.3.2",
+ "express": "4.14.0",
+ "express-session": "^1.6.5",
+ "hogan-express": "0.5.2",
+ "http-proxy-middleware": "^0.17.2",
+ "less": "2.7.1",
+ "moment": "^2.10.6",
+ "node-http-proxy": "^0.2.3",
+ "passport": "0.3.2",
+ "passport-local": "1.0.0",
+ "redis": "2.6.2",
+ "request": "~2.75.0",
+ "sendgrid": "^4.3.0",
+ "twilio": "^2.11.1"
},
"engines": {
"node": ">= 4.0.0",
diff --git a/src/app.coffee b/src/app.coffee
deleted file mode 100644
index 1fc2099c..00000000
--- a/src/app.coffee
+++ /dev/null
@@ -1,151 +0,0 @@
-request = require('request')
-express = require('express')
-bodyParser = require('body-parser')
-cookieParser = require('cookie-parser')
-path = require('path')
-passport = require('./passport')
-config = require('./config')
-fs = require('fs')
-proxyMiddleware = require('http-proxy-middleware')
-sessions = require("./routes/sessions")(passport)
-transactions = require("./routes/transactions")
-twilio = require('twilio')
-users = require("./routes/users")(sessions)
-
-session = require('express-session')
-RedisStore = require('connect-redis')(session)
-sessionStore = new RedisStore(require('./redis').host, ttl: 172800)
-
-
-proxyContext = '/blockcypher'
-proxyOptions =
- target: 'https://api.blockcypher.com'
- changeOrigin: true
- pathRewrite:
- '^/blockcypher/': '/'
- onProxyReq: (proxyReq, req, res) ->
- symbol = if '?' in proxyReq.path then '&' else '?'
- proxyReq.path += "#{symbol}token=#{config.blockcypher_token}"
-
-proxy = proxyMiddleware(proxyContext, proxyOptions)
-
-app = express()
-app.enable('trust proxy')
-app.engine('html', require('hogan-express'))
-app.set('view engine', 'html')
-app.set('views', __dirname + '/views')
-app.use(express.static(__dirname + '/public'))
-app.use(proxy)
-app.use(bodyParser.urlencoded({ extended: true}))
-app.use(bodyParser.json())
-app.use(bodyParser.json({ type: 'application/vnd.api+json' }))
-app.use(cookieParser(config.secret))
-app.use(session(
- resave: true
- saveUninitialized: true
- secret: config.secret
- store: sessionStore
- cookie: maxAge: 1209600000
- key: 'coinos.sid'
-))
-app.use(passport.initialize())
-app.use(passport.session())
-
-authorize = (req, res, next) ->
- if req.params.user is req.user?.username or
- req.user?.username is 'admin'
- return next()
-
- req.session.redirect = req.path
- res.redirect('/login')
-
-cache = (req, res, next) ->
- unless req.path is '/login'
- res.setHeader "Cache-Control", "public, max-age=900"
- next()
-
-do fetchRates = ->
- request("https://api.bitcoinaverage.com/exchanges/all", (error, response, body) ->
- try
- require('util').isDate(JSON.parse(body).timestamp)
- file = 'public/js/rates.json'
- stream = fs.createWriteStream(file)
- fs.truncate(file, 0, ->
- stream.write(body)
- )
- )
- setTimeout(fetchRates, 120000)
-
-require('./bcoin').init(app)
-
-app.get('/', cache, sessions.new)
-
-app.get('/address', cache, (req, res) ->
- res.render('address',
- layout: 'layout',
- js: (-> global.js),
- css: (-> global.css)
- )
-)
-
-app.get('/ticker', cache, (req, res) ->
- fs = require('fs')
- fs.readFile("./public/js/rates.json", (err, data) ->
- req.query.currency ||= 'CAD'
- req.query.symbol ||= 'quadrigacx'
- req.query.type ||= 'bid'
-
- try
- exchange = JSON.parse(data)[req.query.currency][req.query.symbol]['rates'][req.query.type].toString()
- catch e
- exchange = "0"
-
- res.writeHead(200,
- 'Content-Length': exchange.length,
- 'Content-Type': 'text/plain')
- res.write(exchange)
- res.end()
- )
-)
-
-app.get('/tips', cache, (req, res) ->
- res.render('tips',
- notice: true,
- layout: 'layout',
- js: (-> global.js),
- css: (-> global.css)
- )
-)
-
-app.get('/login', cache, sessions.new)
-app.post('/login', sessions.create)
-app.get('/logout', sessions.destroy)
-
-app.get('/users.json', users.index)
-app.get('/register', cache, users.new)
-app.get('/users/new', cache, users.new)
-app.post('/users', users.create)
-app.get('/verify/:token', users.verify)
-
-app.post('/:user', authorize, users.update)
-app.get('/:user/edit', authorize, users.edit)
-app.get('/:user/profile', authorize, users.profile)
-app.get('/:user/wallet', authorize, users.wallet)
-
-app.get('/:user/transactions.json', authorize, transactions.json)
-app.post('/:user/transactions', transactions.create)
-app.post('/transactions/:txid', transactions.update)
-app.delete('/:user/transactions/:txid', transactions.delete)
-app.get('/:user/report', authorize, transactions.index)
-
-app.get('/:user.json', users.json)
-app.get('/:user', cache, users.show)
-
-app.use((err, req, res, next) ->
- res.status(500)
- res.send('An error occurred')
- console.error(err.stack)
- res.end()
-)
-
-app.listen(3000)
diff --git a/src/bcoin.coffee b/src/bcoin.coffee
deleted file mode 100644
index d0a8a089..00000000
--- a/src/bcoin.coffee
+++ /dev/null
@@ -1,87 +0,0 @@
-bcoin = require('bcoin')
-config = require('./config')
-db = require('./redis')
-twilio = require('twilio')
-
-module.exports =
- init: (app) ->
- users = {}
-
- chain = new bcoin.chain(
- db: 'leveldb'
- name: 'spvchain'
- location: __dirname + '/db/spvchain'
- spv: true
- )
-
- pool = new bcoin.pool(
- chain: chain
- spv: true
- size: 1
- maxPeers: 1
- seeds: ['dctrl.ca']
- )
-
- # pool.logger.level = 4
-
- pool.open().then(->
- db.keysAsync("user:*").then((keys) ->
- Promise.all(keys.map((key) ->
- db.hgetallAsync(key).then((user) ->
- if user.address
- pool.watchAddress(user.address)
- users[user.address] =
- email: user.email
- currency: user.currency
- symbol: user.symbol
- phone: user.phone
- )
- ))
- )
-
- pool.connect()
- pool.startSync()
-
- pool.on('error', (err) ->
- console.log(err)
- )
-
- pool.on('tx', (tx) ->
- for output in tx.outputs
- value = (output.value / 100000000).toFixed(8)
- address = output.getAddress().toBase58()
- if Object.keys(users).includes(address)
- app.render('payment', { value: value, address: address }, (err, html) ->
- helper = require('sendgrid').mail
- from_email = new helper.Email('[email protected]')
- to_email = new helper.Email(users[address].email)
- subject = 'Received Payment'
- content = new helper.Content('text/html', html)
- mail = new helper.Mail(from_email, subject, to_email, content)
-
- sg = require('sendgrid')(config.sendgrid_token)
- request = sg.emptyRequest(
- method: 'POST'
- path: '/v3/mail/send'
- body: mail.toJSON()
- )
-
- sg.API(request, (error, response) ->
- console.log(response.statusCode)
- console.log(response.body)
- console.log(response.headers)
- )
- )
-
- if users[address].phone
- client = new twilio.RestClient(config.twilio_sid, config.twilio_token)
-
- client.messages.create(
- to: user.phone
- from: config.twilio_number
- body: "You received a payment of #{value} BTC"
- , (err, message) ->
- console.log(message.sid)
- )
- )
- )
diff --git a/src/components/SignUp.vue b/src/components/SignUp.vue
new file mode 100644
index 00000000..51583b82
--- /dev/null
+++ b/src/components/SignUp.vue
@@ -0,0 +1,39 @@
+<template lang="pug">
+div
+ #main-logo
+ form#register(action='/users', method='post')
+ .form-group
+ label(for='username') Username:
+ |
+ input#username.form-control(type='text', name='username')
+ .form-group
+ label(for='email') Email:
+ |
+ input#email.form-control(type='text', name='email')
+ .form-group
+ label(for='password') Passphrase:
+ |
+ input#password.form-control(type='password', name='password')
+ #messages
+ .form-group
+ label(for='confirm') Confirm Passphrase:
+ |
+ input#confirm.form-control(type='password', name='confirm')
+ |
+ input#commission(name='commission', type='hidden', value='0')
+ |
+ input#unit(name='unit', type='hidden', value='BTC')
+ |
+ input#pubkey(name='pubkey', type='hidden')
+ |
+ input#privkey(name='privkey', type='hidden')
+ |
+ input.btn.btn-primary(type='submit', value='Register')
+ #qr
+</template>
+
+<script>
+export default {
+ name: 'SignUp'
+}
+</script>
diff --git a/src/install.coffee b/src/install.coffee
deleted file mode 100644
index 7ba2449d..00000000
--- a/src/install.coffee
+++ /dev/null
@@ -1,16 +0,0 @@
-db = require("./redis")
-bcrypt = require('bcryptjs')
-
-db.get("user:admin", (err, res) ->
- if !res
- bcrypt.hash('admin', 12, (err, hash) ->
- db.sadd("users","user:admin")
- db.hmset("user:admin",
- username: 'admin'
- password: hash,
- , ->
- console.log("Created admin user with password 'admin'")
- process.exit()
- )
- )
-)
diff --git a/src/main.js b/src/main.js
index 0fb682f3..cfaeb1ac 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,18 +1,18 @@
-// The Vue build version to load with the `import` command
-// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
import SignIn from './components/SignIn'
+import SignUp from './components/SignUp'
import Sales from './components/Sales'
const routes = [
- { path: '/', component: SignIn },
+ { path: '/signin', component: SignIn },
+ { path: '/signup', component: SignUp },
{ path: '/sales', component: Sales }
]
const router = new VueRouter({
- routes // short for routes: routes
+ routes
})
Vue.use(VueRouter)
@@ -24,4 +24,3 @@ new Vue({
components: { App },
router: router
})
-
diff --git a/src/passport.coffee b/src/passport.coffee
deleted file mode 100644
index 7fd99668..00000000
--- a/src/passport.coffee
+++ /dev/null
@@ -1,35 +0,0 @@
-db = require("redis").createClient()
-bcrypt = require('bcryptjs')
-
-passport = require('passport')
-LocalStrategy = require('passport-local').Strategy
-
-passport.serializeUser((user, done) ->
- done(null, user.username.toLowerCase())
-)
-
-passport.deserializeUser((username, done) ->
- db.hgetall("user:"+username.toLowerCase(), (err, user) ->
- return done(null, user)
- )
-)
-
-passport.use(new LocalStrategy(
- (username, password, done) ->
- db.hget("user:"+username.toLowerCase(), 'password', (err, hash) ->
- return done(err) if err
- if hash
- bcrypt.compare(password, hash, (err, match) ->
- if match
- db.hgetall("user:"+username.toLowerCase(), (err, user) ->
- return done(null, user)
- )
- else
- return done(null, false)
- )
- else
- return done(null, false)
- )
-))
-
-module.exports = passport
diff --git a/src/redis.coffee b/src/redis.coffee
deleted file mode 100644
index 7f28fae0..00000000
--- a/src/redis.coffee
+++ /dev/null
@@ -1,7 +0,0 @@
-Promise = require('bluebird')
-
-settings =
- port: 6379
- host: '127.0.0.1'
-
-module.exports = Promise.promisifyAll(require('redis')).createClient(settings.port, settings.host)
diff --git a/src/routes/sessions.coffee b/src/routes/sessions.coffee
deleted file mode 100644
index 70c18b4e..00000000
--- a/src/routes/sessions.coffee
+++ /dev/null
@@ -1,25 +0,0 @@
-module.exports = (passport) ->
- new: (req, res) ->
- res.render('sessions/new',
- js: (-> global.js),
- css: (-> global.css)
- )
-
- create: (req, res, next) ->
- passport.authenticate('local', (err, user, info) ->
- if (err)
- return next(err)
- if (!user)
- return res.redirect('/login')
- req.login(user, (err) ->
- if (err)
- return next(err)
- url = req.headers['referer']
- url = "/#{user.username}" unless /edit/.test(url)
- return res.redirect(url)
- )
- )(req, res, next)
-
- destroy: (req, res) ->
- req.logout()
- res.redirect('/login')
diff --git a/src/routes/transactions.coffee b/src/routes/transactions.coffee
deleted file mode 100644
index 2eca7766..00000000
--- a/src/routes/transactions.coffee
+++ /dev/null
@@ -1,105 +0,0 @@
-Promise = require('bluebird')
-db = require('../redis')
-config = require("../config")
-moment = require('moment')
-
-txid = (transaction, user) ->
- return transaction if transaction.match(/[a-z]/i)
- return user + ":transactions:" + transaction
-
-module.exports =
- index: (req, res) ->
- res.render(
- 'transactions/index'
- user: req.params.user
- currency: req.session.user.currency
- layout: 'layout'
- navigation: true
- js: (-> global.js)
- css: (-> global.css)
- )
-
- json: (req, res) ->
- result = 'transactions': []
- promises = []
- pattern = req.params.user
- if req.session.user.username is 'admin'
- x = '*'
-
- db.keysAsync("#{pattern}:transactions").then((keys) ->
- Promise.all(keys.map((key) ->
- user = key.substr(0, key.indexOf(':'))
- db.lrangeAsync(key, 0, -1).then((transactions) ->
- Promise.all(transactions.map((transaction) ->
- db.hgetallAsync(txid(transaction, user)).then((transaction) ->
- if transaction
- transaction.user = user
- result.transactions.push(transaction)
- )
- ))
- )
- ))
- ).then(->
- res.write(JSON.stringify(result))
- res.end()
- )
-
-
- create: (req, res) ->
- finish = ->
- db.hgetall("user:"+req.params.user.toLowerCase(), (err, user) ->
- res.render('transactions/notification',
- layout: 'mail'
- amount: (req.body.received * req.body.exchange).toFixed(2).toString() + ' ' + user.currency
- address: req.body.address
- txid: req.body.txid
- js: (-> global.js)
- css: (-> global.css)
- (err, html) ->
- helper = require('sendgrid').mail
- from_email = new helper.Email('[email protected]')
- to_email = new helper.Email(user.email)
- subject = 'Payment Received'
- content = new helper.Content('text/html', html)
- mail = new helper.Mail(from_email, subject, to_email, content)
-
- sg = require('sendgrid')(config.sendgrid_token)
- request = sg.emptyRequest(
- method: 'POST'
- path: '/v3/mail/send'
- body: mail.toJSON()
- )
-
- sg.API(request, (error, response) ->
- console.log(response.statusCode)
- console.log(response.body)
- console.log(response.headers)
- )
- )
- )
- res.write(JSON.stringify(req.body))
- res.end()
-
- db.watch(req.body.txid)
- db.exists(req.body.txid, (err, result) ->
- return finish() if result
-
- multi = db.multi()
- multi.hmset(req.body.txid, req.body)
- multi.rpush("#{req.params.user}:transactions", req.body.txid)
- multi.exec((err, replies) ->
- finish()
- )
- )
-
- update: (req, res) ->
- db.hset(req.params.txid, 'notes', req.body.notes, ->
- res.end()
- )
-
- delete: (req, res) ->
- db.del(req.params.txid, ->
- db.lrem(req.params.user + ":transactions", 0, req.params.txid, ->
- res.end()
- )
- )
diff --git a/src/routes/users.coffee b/src/routes/users.coffee
deleted file mode 100644
index 1611f691..00000000
--- a/src/routes/users.coffee
+++ /dev/null
@@ -1,31 +0,0 @@
-db = require("redis").createClient()
-bcrypt = require('bcrypt')
-
-module.exports = (sessions) ->
- exists: (req, res) ->
- db.hgetall(req.params.user, (err, obj) ->
- if obj? then res.write('true') else res.write('false')
- res.end()
- )
-
- new: (req, res) ->
- res.render('users/new',
- js: (-> global.js),
- css: (-> global.css),
- )
-
- create: (req, res) ->
- db.hgetall(req.body.username, (err, obj) ->
- if obj
- res.redirect(req.body.username)
- else
- bcrypt.hash(req.body.password, 12, (err, hash) ->
- db.hmset(
- req.body.username,
- {username: req.body.username, password: hash},
- ->
- req.headers['referer'] = "/#{req.body.username}/edit"
- sessions.create(req, res)
- )
- )
- )
diff --git a/static/js/calculator.coffee b/static/js/calculator.coffee
deleted file mode 100644
index 75192596..00000000
--- a/static/js/calculator.coffee
+++ /dev/null
@@ -1,268 +0,0 @@
-EXCHANGE_FAIL = "Problem fetching exchange rate"
-SOCKET_FAIL = "Problem connecting to payment server, notifications may not appear"
-ADDRESS_FAIL = "Invalid address"
-API_URL = "wss://socket.blockcypher.com/v1/btc/main"
-TEST_URL = "wss://socket.blockcypher.com/v1/btc/test3"
-
-g = exports ? this
-g.errors = []
-g.amount_requested = 0
-g.amount = 0.toFixed(2)
-g.tip = 1
-g.transactions = []
-
-$(->
- $.ajax(
- url: $('#user').val() + '.json',
- dataType: 'json',
- success: (data) ->
- g.user = data
- setup()
- )
-
- $('button').click((e) ->
- e.preventDefault()
- )
-
- $('.numpad .btn').off('click').click((e) ->
- e.preventDefault()
-
- m = $(this).html()
- n = parseFloat($('.amount').html())
-
- if m is 'C'
- g.amount = 0.toFixed(2)
- updateTotal()
- return
-
- return if n > 10000000
-
- if m is '00'
- n = 100 * n
- else
- n = 10 * n + parseFloat(m) / 100
-
- g.amount = n.toFixed(2)
-
- updateTotal()
- )
-
- $('.numpad .btn:last').off('click').click((e) ->
- e.preventDefault()
-
- g.amount = (Math.floor(100 * (parseFloat($('.amount').html()) / 10)) / 100).toFixed(2)
- updateTotal()
- )
-
- $('.tippad .btn').off('click').click((e) ->
- e.preventDefault()
-
- text = $(this).html()
- if text is 'No Tip'
- value = 0
- else
- value = text.slice(1, -1)
-
- $(this).addClass('active')
- $(this).siblings().removeClass('active')
- g.tip = 1 + (parseFloat(value)/100)
- updateTotal()
- )
-
- $('#received').click(-> window.location = "/#{g.user.username}/report")
- $('#slide').click(->
- $('#controls').slideToggle()
- $(this).find('i').toggleClass('fa-sort-up').toggleClass('fa-sort-down')
- )
-)
-
-setup = ->
- g.user.address or= ''
- g.user.commission or= 0
- g.user.currency or= 'CAD'
- g.user.symbol or= 'quadrigacx'
- g.user.unit or= 'BTC'
-
- if g.user.title
- $('#title').html("<a href='/#{g.user.username}/edit'>#{g.user.title}</a>").show()
-
- if g.user.logo
- ext = g.user.logo.substr(g.user.logo.length - 3)
- src = "/img/logos/#{g.user.username}.#{ext}"
- $('#logo').attr('src', src).show()
-
- getAddress()
- if g.user.address[0] is 'm'
- API_URL = TEST_URL
-
- $('.symbol').html(g.user.currency)
- $('.currency').html(g.user.currency)
- $('.unit').html(g.user.unit)
-
- $('#received').hide()
-
- fetchExchangeRate()
- listen()
-
-fetchExchangeRate = ->
- $.ajax(
- url: "ticker?currency=#{g.user.currency}&symbol=#{g.user.symbol}&type=bid",
- success: (exchange) ->
- if exchange?
- clear(EXCHANGE_FAIL)
- else
- fail(EXCHANGE_FAIL)
- return
-
- g.exchange = (exchange - exchange * g.user.commission * 0.01).toFixed(2)
- $('#exchange').html(g.exchange)
- updateTotal()
-
- unless g.setupComplete
- g.setupComplete = true
-
- error: -> fail(EXCHANGE_FAIL)
- )
- setTimeout(fetchExchangeRate, 900000)
-
-updateTotal = ->
- precision = 9 - multiplier().toString().length
- subtotal = parseFloat(g.amount * g.tip).toFixed(2)
- total = (subtotal * multiplier() / g.exchange).toFixed(precision)
- g.amount_requested = (subtotal / g.exchange).toFixed(8)
-
- unless $.isNumeric(total)
- total = ''
-
- $('#received').hide()
- $('#payment').fadeIn('slow')
-
- $('.tip').html((subtotal - g.amount).toFixed(2))
- $('.subtotal').html(subtotal.toString())
- $('.amount').html(g.amount)
- $('.exchange').html(g.exchange)
- $('.symbol').html(g.user.symbol)
-
- if g.user.commission < 0
- $('.commission').html("+#{Math.abs(g.user.commission)}%")
-
-
- $('#total').html(total.toString())
-
- size = 300
- $('#qr').css('height', size)
-
- time = 0
- if g.timeout
- time = 10
-
- clearTimeout(g.timeout)
- g.timeout = setTimeout(->
- $('#qr').html('')
- new QRCode('qr',
- text: "bitcoin:#{g.user.address}?amount=#{g.amount_requested.toString()}"
- width: size
- height: size
- )
- , time)
-
-listen = ->
- g.attempts++
- if g.blockchain and g.blockchain.readyState is 1
- setTimeout(listen, 12000)
- else
- fail(SOCKET_FAIL) if g.attempts > 3
- g.blockchain = new WebSocket(API_URL)
-
- g.blockchain.onopen = ->
- if g.blockchain.readyState is 1
- g.attempts = 0
- clear(SOCKET_FAIL)
- g.blockchain.send('{"event":"unconfirmed-tx", "address":"' + g.user.address + '"}')
- else
- setTimeout(g.blockchain.onopen, 12000 * g.attempts)
-
- g.blockchain.onerror = ->
- fail(SOCKET_FAIL)
- g.blockchain.close()
- delete g.blockchain
- listen()
-
- g.blockchain.onclose = ->
- delete g.blockchain
- listen()
-
- g.blockchain.onmessage = (e) ->
- tx = JSON.parse(e.data)
- amount = 0
-
- return if tx.hash == g.last_seen
- g.last_seen = tx.hash
-
- for output in tx.outputs
- if (output.addresses[0] == g.user.address)
- amount += output.value / 100000000
-
- logTransaction(tx.hash, amount)
-
-logTransaction = (txid, amount) ->
- if $('#received').is(":hidden") and amount >= g.amount_requested
- $('#payment').hide()
- $('#received').fadeIn('slow')
- $('#success')[0].play()
- g.user.index++
-
- if g.transactions.indexOf(txid) is -1
- g.transactions.push(txid)
- $.post("/#{g.user.username}/transactions",
- txid: txid,
- address: g.user.address,
- date: moment().format("YYYY-MM-DD HH:mm:ss"),
- received: amount,
- exchange: g.exchange
- tip: g.tip
- )
-
- getAddress()
-
-getAddress = ->
- try
- bitcoin.address.fromBase58Check(g.user.pubkey)
- g.user.address = g.user.pubkey
- catch
- master = bitcoin.HDNode.fromBase58(g.user.pubkey)
- child = master.derive(0).derive(g.user.index)
- g.user.address = child.getAddress().toString()
- g.blockchain.close() if g.blockchain
- listen()
-
- $('#address').html("<a href='https://blockchain.info/address/#{g.user.address}'>#{g.user.address}</a>")
-
-fail = (msg) ->
- g.errors.push(msg)
- g.errors = g.errors.uniq()
- $('#error').show().html(g.errors.toString())
-
-clear = (msg) ->
- i = g.errors.indexOf(msg)
- g.errors.splice(i, 1) if i >= 0
- if (g.errors.length > 0)
- $('#error').show().html(g.errors.toString())
- else
- $('#error').hide()
- $('#calculator').fadeIn('slow')
-
-Array::uniq = ->
- output = {}
- output[@[key]] = @[key] for key in [0...@length]
- value for key, value of output
-
-multiplier = ->
- switch g.user.unit
- when 'BTC' then 1
- when 'mBTC' then 1000
- when 'µBTC' then 1000000
- when 'bits' then 1000000
- when 'satoshis' then 100000000
-
-
diff --git a/static/js/generate_address.coffee b/static/js/generate_address.coffee
deleted file mode 100644
index face65ea..00000000
--- a/static/js/generate_address.coffee
+++ /dev/null
@@ -1,74 +0,0 @@
-g = this
-
-$(->
- genKey()
- $('.regenerate').click(genKey)
-
- $('#encrypt').submit(->
- $('.form-control').blur()
- if $('.has-error').length > 0
- $('.has-error').effect('shake', 500)
- return false
-
- $('#modal').modal()
- return false
- )
-
- $('#modal').on('shown.bs.modal', ->
- bip38 = new Bip38
- g.enc_privkey = bip38.encrypt(g.privkey, $('#password').val(), g.pubkey)
- $('#modal-body').html('Done!')
- setTimeout(
- -> $('#modal').modal('hide')
- 1000
- )
- )
-
- $('#modal').on('hidden.bs.modal', ->
- if $('#password').val() == ''
- g.enc_privkey = g.privkey
- $('#status').html('')
- else
- $('#status').html('Encrypted')
-
- $('#privkey').html(g.enc_privkey)
- $('#privqr').html('')
- new QRCode('privqr', text: $('#privkey').html(), width: 260, height: 260)
- )
-
- $('.print').click(-> window.print())
- $('#password').pwstrength(showVerdicts: false)
- $('#password').blur(->
- $('#confirm').blur()
- $(this).parent().next('.alert').remove()
-
- if $('.progress-bar-success').length > 0
- $(this).parent().removeClass('has-error')
- else
- $(this).parent().addClass('has-error')
- )
- $('#confirm').blur(->
- if $('#password').val() == $('#confirm').val()
- $('#confirm').parent().removeClass('has-error')
- else
- $('#confirm').parent().addClass('has-error')
- )
-)
-
-genKey = ->
- $('#password').focus()
- key = bitcoin.ECKey.makeRandom(false)
- g.privkey = key.toWIF()
- g.pubkey = key.pub.getAddress().toString()
-
- $('#pubkey').html(g.pubkey)
- $('#privkey').html(g.privkey)
-
- $('#pubqr, #privqr, #status').html('')
- $('#password, #confirm').val('').keyup().parent().removeClass('has-error')
-
- new QRCode('pubqr', text: $('#pubkey').html(), width: 260, height: 260)
- new QRCode('privqr', text: $('#privkey').html(), width: 260, height: 260)
-
-
-
diff --git a/static/js/index.coffee b/static/js/index.coffee
deleted file mode 100644
index 090abbe2..00000000
--- a/static/js/index.coffee
+++ /dev/null
@@ -1,44 +0,0 @@
-#= require js/jquery-1.8.2.min.js
-#= require js/bootstrap.min.js
-
-g = exports ? this
-
-$(->
- fetchExchangeRate('ask')
- fetchExchangeRate('bid')
-
- $('#username').blur(->
- $.get(
- "/#{$(this).val()}/exists",
- username: $(this).val(),
- (data) ->
- if data is "true"
- $('#username').prev().css('color', 'red').html('Username (taken)')
- g.preventSubmit = true
- else
- $('#username').prev().css('color', 'black').html('Username')
- g.preventSubmit = false
- )
- )
-
- $('#signup').submit(->
- return false if g.preventSubmit
- return true
- )
-)
-
-fetchExchangeRate = (type) ->
- commission = 0.015
- commission *= -1 if type is 'bid'
-
- $.ajax(
- url: "/ticker?symbol=virtexCAD&type=#{type}&amount=100",
- success: (exchange) ->
- if not exchange?
- exchange = '??'
-
- exchange = exchange - exchange * commission
- $("##{type}").html(exchange.toFixed(2))
- error: ->
- $("##{type}").html('??')
- )
diff --git a/static/js/profile.coffee b/static/js/profile.coffee
deleted file mode 100644
index a894f275..00000000
--- a/static/js/profile.coffee
+++ /dev/null
@@ -1,30 +0,0 @@
-g = exports ? this
-g.proceed = false
-
-$(->
- $('[data-toggle=popover]').popover()
- $('#title').focus()
-
- user = $('#username').val()
- $.getJSON("/#{user}.json", (data) ->
- $('#email').val(data.email)
- $('#phone').val(data.phone)
- $('#profile').fadeIn()
- )
-
- $('#confirm').blur(->
- $('#confirm_error').remove()
- if $('#password').val() != $('#confirm').val()
- $('#password, #confirm').parent().addClass('has-error')
- $('#confirm').parent().after('<div id="confirm_error" class="alert alert-danger">Passwords don\'t match</div>')
- else
- $('#password, #confirm').parent().removeClass('has-error')
- )
-
- $('#profile').submit(->
- $('#profile .form-control').blur()
- if $('#profile .has-error').length > 0
- $('#profile .has-error').effect('shake', 500)
- return false
- )
-)
diff --git a/static/js/register.coffee b/static/js/register.coffee
deleted file mode 100644
index 98842328..00000000
--- a/static/js/register.coffee
+++ /dev/null
@@ -1,53 +0,0 @@
-g = this
-
-$(->
- $('#username').focus()
-
- $('#username').blur(->
- $(this).parent().next('.alert').remove()
-
- if /^[a-z]+$/.test($(this).val())
- $(this).parent().removeClass('has-error')
- else
- $(this).parent().addClass('has-error')
- $(this).parent().after('<div class="alert alert-danger">Username must be lowercase</div>')
- )
-
- $('#password').blur(->
- $('#confirm').blur()
- $(this).parent().next('.alert').remove()
- )
-
- $('#confirm').blur(->
- return if $(this).val() == ''
- $(this).parent().next('.alert').remove()
-
- if $('#password').val() == $('#confirm').val()
- $('#confirm').parent().removeClass('has-error')
- else
- $('#confirm').parent().addClass('has-error')
- $('#confirm').parent().after('<div class="alert alert-danger">Passwords don\'t match</div>')
- )
-
- $('#email').blur(->
- return if $(this).val() == ''
- $(this).parent().next('.alert').remove()
- if validateEmail($(this).val())
- $(this).parent().removeClass('has-error')
- else
- $(this).parent().addClass('has-error')
- $(this).parent().after('<div class="alert alert-danger">Invalid email</div>')
- )
-
- $('#register').submit(->
- $('.form-control').blur()
- if $('.has-error').length > 0
- $('.has-error').effect('shake', 500)
- return false
- else
- mnemonic = bip39.generateMnemonic()
- key = bitcoin.HDNode.fromSeedBuffer(bip39.mnemonicToSeed(mnemonic)).deriveHardened(44).deriveHardened(0)
- $('#pubkey').val(key.neutered().toString())
- $('#privkey').val(CryptoJS.AES.encrypt(key.toString(), $('#password').val()).toString())
- )
-)
diff --git a/static/js/setup.coffee b/static/js/setup.coffee
deleted file mode 100644
index d796c897..00000000
--- a/static/js/setup.coffee
+++ /dev/null
@@ -1,65 +0,0 @@
-g = exports ? this
-g.proceed = false
-
-$(->
- $('#encryption-password').pwstrength(showVerdicts: false)
-
- $.getJSON("/js/rates.json", (data) ->
- currencies = Object.keys(data)
- currencies = currencies.sort()
- currencies.pop()
-
- $.each(currencies, (i, v) ->
- $('#currency').append("<option value='#{v}'>#{v}</option>")
- )
- $("#currency option[value='CAD']").attr('selected', 'selected')
-
- $('#currency').change(->
- currency = $(this).val()
- return unless currency
-
- $('#symbol option').remove()
- symbols = Object.keys(data[currency])
- $.each(symbols, (i, v) ->
- return if v == 'localbitcoins'
- $('#symbol').append("<option value='#{v}'>#{v}</option>")
- )
-
- switch currency
- when 'CAD'
- $("#symbol option[value='quadrigacx']").attr('selected', 'selected')
- when 'USD'
- $("#symbol option[value='bitstamp']").attr('selected', 'selected')
- )
-
- user = $('#username').val()
- $.getJSON("/#{user}.json", (data) ->
- data.commission ?= 0
- data.unit ?= 'BTC'
- $('#email').val(data.email)
- $('#title').val(data.title)
- $('#logo').val(data.logo)
- $('#address').val(data.address)
- $('#commission').val(data.commission)
- $('#unit').val(data.unit)
- $("#currency option[value='#{data.currency}']").attr('selected', 'selected')
- $('#currency').change()
- $("#symbol option[value='#{data.symbol}']").attr('selected', 'selected')
- $('#setup').fadeIn()
- $('#title').focus()
- )
- )
-
- units = ['BTC', 'mBTC', '&micro;BTC', 'bits', 'satoshis']
- $.each(units, (i, v) ->
- $('#unit').append("<option value='#{v}'>#{v}</option>")
- )
-
- $('#setup').submit(->
- $('#setup .form-control').blur()
- if $('#setup .has-error').length > 0
- $('#setup .has-error').effect('shake', 500)
- return false
- )
-)
-
diff --git a/static/js/setup.js b/static/js/setup.js
index e96bd00d..63b9e291 100644
--- a/static/js/setup.js
+++ b/static/js/setup.js
@@ -11,7 +11,7 @@
$('#encryption-password').pwstrength({
showVerdicts: false
});
- $.getJSON("/js/rates.json", function(data) {
+ $.getJSON("/rates", function(data) {
var currencies, user;
currencies = Object.keys(data);
currencies = currencies.sort();
@@ -79,4 +79,4 @@
},{}]},{},[1])
-; \ No newline at end of file
+;
diff --git a/static/js/signin.coffee b/static/js/signin.coffee
deleted file mode 100644
index df7dbb39..00000000
--- a/static/js/signin.coffee
+++ /dev/null
@@ -1,6 +0,0 @@
-$(->
- $('#register').click(->
- window.location.href = '/register'
- $(this).preventDefault()
- )
-)
diff --git a/static/js/wallet.coffee b/static/js/wallet.coffee
deleted file mode 100644
index 1beefd23..00000000
--- a/static/js/wallet.coffee
+++ /dev/null
@@ -1,456 +0,0 @@
-g = exports ? this
-g.proceed = false
-g.api = '/blockcypher/v1/btc/main'
-
-validators =
- address: (e) ->
- return true if e.val() is ''
- try
- bitcoin.address.fromBase58Check(e.val())
- catch
- return false
-
- key: (e) ->
- $('#keytype').val() != 'unknown'
-
-errors =
- address: 'Invalid address.'
- key: 'Could not detect key type.'
-
-$(->
- getUser()
-
- $('#types').attr('data-content', """
- Bitcoin Address (starts with 1 or 3)<br />
- Private Key (starts with 5 or L)<br />
- HD Wallet pubkey (starts with xpub)<br />
- HD Wallet private key (starts with xprv)<br />
- AES Encrypted Private Key (starts with U)<br />
- BIP38 Encrypted Private Key (starts with 6)<br />
- BIP39 Mnemonic (series of 12-24 english words)
- """)
- .popover(html: true)
- .on("show.bs.popover", -> $(this).data("bs.popover").tip().css(minWidth: "400px"))
-
- $('form').validator(custom: validators, errors: errors, delay: 1200)
- $('[data-toggle=tooltip]').tooltip(trigger: 'hover')
-
- $('#key').keyup(->
- val = $(this).val()
-
- $('#keytype').val('unknown')
-
- switch val[0]
- when '1'
- try
- bitcoin.address.fromBase58Check(val)
- $('#keytype').val('address')
- when 'm'
- try
- bitcoin.address.fromBase58Check(val)
- $('#keytype').val('address')
- when '5', \
- 'L', \
- 'K'
- try
- bitcoin.ECPair.fromWIF(val)
- $('#keytype').val('wif')
- when 'U'
- try
- if CryptoJS.AES.decrypt(val, g.password).toString(CryptoJS.enc.Utf8)
- $('#keytype').val('aes')
- when '6'
- if bip38().verify(val)
- $('#keytype').val('bip38')
- when 'x'
- if $(this).val()[3] is 'b'
- try
- bitcoin.HDNode.fromBase58(val)
- $('#keytype').val('xpub')
- else
- try
- bitcoin.HDNode.fromBase58(val)
- $('#keytype').val('xprv')
- else
- if val.split(' ').length in [12, 15, 18, 21, 24] and bip39.validateMnemonic(val)
- $('#keytype').val('bip39')
- )
-
- $('#save').click(->
- $('.form-control').blur()
- if $('#keys .has-error').length > 0
- $('#keys .has-error').effect('shake', 500)
- return
-
- key = $('#key').val()
- proceed = true
-
- switch $('#keytype').val()
- when 'address'
- $('#pubkey').val(key)
- $('#privkey').val('')
- when 'wif'
- pubkey = bitcoin.ECPair.fromWIF(key).getAddress()
- privkey = CryptoJS.AES.encrypt(key, g.password)
- $('#pubkey').val(pubkey)
- $('#privkey').val(privkey)
- when 'aes'
- try
- pubkey = bitcoin.HDNode.fromBase58(CryptoJS.AES.decrypt(key, g.password).toString(CryptoJS.enc.Utf8)).neutered().toString()
- $('#pubkey').val(pubkey)
- $('#privkey').val(key)
- catch
- try
- pubkey = bitcoin.ECPair.fromWIF(CryptoJS.AES.decrypt(key, g.password).toString(CryptoJS.enc.Utf8)).getAddress()
- $('#pubkey').val(pubkey)
- $('#privkey').val(key)
- catch
- proceed = false
- when 'bip38'
- wif = bip38().decrypt(key, g.password)
- pubkey = bitcoin.ECPair.fromWIF(wif).getAddress()
- privkey = CryptoJS.AES.encrypt(wif, g.password)
- $('#pubkey').val(pubkey)
- $('#privkey, #key').val(privkey)
- when 'xpub'
- $('#pubkey').val(key)
- $('#privkey').val('')
- when 'xprv'
- pubkey = bitcoin.HDNode.fromBase58(key).neutered().toString()
- privkey = CryptoJS.AES.encrypt(key, g.password)
- $('#pubkey').val(pubkey)
- $('#privkey').val(privkey)
- when 'bip39'
- master = bitcoin.HDNode.fromSeedBuffer(bip39.mnemonicToSeed(key)).deriveHardened(44).deriveHardened(0)
- pubkey = master.neutered().toString()
- privkey = CryptoJS.AES.encrypt(master.toString(), g.password)
- $('#pubkey').val(pubkey)
- $('#privkey').val(privkey)
-
- if proceed
- updateUser()
- $('#keys').hide()
- $('#keys_updated').fadeIn()
- $('#balances').hide()
- $('#fetching').show()
- )
-
-
- $('#withdrawal form input[type=button]').click(sendTransaction)
-
- $('#currency_toggle').click(->
- if $(this).html() is g.user.unit
- $(this).html(g.user.currency)
- g.amount = parseFloat($('#amount').val()).toFixed(precision())
- amount = (g.amount * g.exchange / multiplier()).toFixed(2)
- $('#amount').val(amount)
- $('#amount').attr('step', 0.01)
- $('#amount').attr('max', (g.balance * g.exchange / multiplier()).toFixed(2))
- else
- $(this).html(g.user.unit)
- $('#amount').val(convertedAmount())
- $('#amount').attr('step', 0.00000001 * multiplier())
- $('#amount').attr('max', g.balance)
- )
-
- $('#max').click(->
- if $('#currency_toggle').html() is g.user.unit
- $('#amount').val(g.balance).blur()
- else
- g.amount = parseFloat(g.balance).toFixed(precision())
- amount = (g.balance / multiplier() * g.exchange).toFixed(2)
- $('#amount').val(amount).blur()
- )
-
- $('#amount').change(->
- if $('#currency_toggle').html() is g.user.unit
- $(this).val(parseFloat($(this).val()).toFixed(precision()))
- else
- $(this).val(parseFloat($(this).val()).toFixed(2))
-
- if parseFloat($(this).val()) > parseFloat($(this).attr('max'))
- $(this).val($(this).attr('max'))
- )
-
- $('#password').keyup(->
- try
- if g.user.privkey
- g.privkey = CryptoJS.AES.decrypt(g.user.privkey, $(this).val()).toString(CryptoJS.enc.Utf8)
-
- if g.privkey[0] is 'x'
- g.key = bitcoin.HDNode.fromBase58(g.privkey)
- else
- g.key = bitcoin.ECPair.fromWIF(g.privkey)
-
- $('#key').val(g.privkey).keyup()
- else
- $('#key').val(g.user.pubkey).keyup()
-
- $(this).closest('.form-group').hide()
- $('.wallet').fadeIn()
- g.password = $(this).val()
- )
-
- $('#manage').click(->
- $('#withdrawal').hide()
- $('#keys').show()
- $('#privkey').val(g.user.privkey)
- )
-
- $('#withdraw').click(->
- $('#withdrawal').show()
- $('#amount').focus()
- $('#keys').hide()
- $('#withdrawal form').validator('destroy')
- $('#withdrawal form').validator(custom: validators, errors: errors, delay: 1200)
- )
-
- $('#cancel').click(->
- $('#keys').hide()
- if g.balance > 0 and g.user.privkey
- $('#withdrawal form').validator('destroy')
- $('#withdrawal form').validator(custom: validators, errors: errors, delay: 1200)
- $('#withdrawal').show()
- $('#amount').focus()
- )
-
- $('#backup').click(->
- url = 'data:application/json;base64,' + btoa(JSON.stringify(g.user.privkey))
- a = document.createElement('a')
- a.setAttribute('href', url)
- a.setAttribute('download', 'wallet.json.aes')
- a.click()
- )
-
- $('#generate').click(->
- bootbox.confirm('<h3>Are you sure?</h3> <p>This will overwrite your existing wallet so make sure that you have the backup we sent to your email in case you want to restore it.</p>', (result) ->
- if result
- mnemonic = bip39.generateMnemonic()
- key = bitcoin.HDNode.fromSeedBuffer(bip39.mnemonicToSeed(mnemonic)).deriveHardened(44).deriveHardened(0)
- $('#key').val(key.toString()).effect('highlight', {}, 2000).keyup()
- )
- )
-
- $('.close').on('click', -> $(this).closest('.alert').fadeOut())
-)
-
-getUser = ->
- $.getJSON("/#{$('#username').val()}.json", (user) ->
- g.user = user
- $('#key').val(user.pubkey)
- $('#pubkey').val(user.pubkey)
- $('#privkey').val(user.privkey)
- $('#address').val(user.address)
- $('.address').html(user.address)
- $('#unit').html(user.unit)
- $('#currency_toggle').html(user.unit)
- $('#amount').attr('step', 0.00000001 * multiplier())
- $('#password').closest('.form-group').show()
- $('#password').focus()
-
- getExchangeRate()
- $('#password').keyup()
- )
-
-getExchangeRate = ->
- $.get("/ticker?currency=#{g.user.currency}&symbol=#{g.user.symbol}&type=bid", (exchange) ->
- g.exchange = exchange
- createWallet()
- )
-
-createWallet = ->
- $.get("#{g.api}/wallets", (data) ->
- if g.user.username in data.wallet_names
- getBalance()
- else
- params = name: g.user.username
-
- if isBip32(g.user.pubkey)
- params.extended_public_key = g.user.pubkey
- params.subchain_indexes = [0,1]
-
- $.post("#{g.api}/wallets/hd", JSON.stringify(params)).done(getBalance).fail(-> $('.wallet').fadeIn())
- else
- params.addresses = [g.user.pubkey]
- $.post("#{g.api}/wallets", JSON.stringify(params)).done(getBalance).fail(-> $('.wallet').fadeIn())
- )
-
-
-getBalance = ->
- $.get("#{g.api}/addrs/#{g.user.username}/balance?omitWalletAddresses=true", (data) ->
- balance = data.final_balance
- g.balance = parseFloat(balance.toBTC())
- fiat = balance.toFiat()
- $('#balance').html(g.balance)
- $('#fiat').html("#{fiat} #{g.user.currency}")
- $('#amount').attr('max', g.balance)
- $('#balances').show()
- $('#fetching').hide()
-
- if g.balance > 0 and g.user.privkey
- $('#keys').hide()
- $('#withdrawal form').validator('destroy')
- $('#withdrawal form').validator(custom: validators, errors: errors, delay: 1200)
- $('#withdrawal').show()
- $('#amount').focus()
- )
-
-updateUser = ->
- data = $('#keys form').serializeObject()
- delete data['key']
-
- $.post("/#{g.user.username}", data, ->
- $.ajax(
- url: "#{g.api}/wallets/#{g.user.username}"
- type: 'DELETE'
- ).always(->
- $.ajax(
- url: "#{g.api}/wallets/hd/#{g.user.username}"
- type: 'DELETE'
- ).always(->
- getUser()
- )
- )
- )
-
-sendTransaction = ->
- if g.key and not (typeof g.key.d is 'undefined' and typeof g.key.keyPair.d is 'undefined')
- dialog = new BootstrapDialog(
- title: '<h3>Confirm Transaction</h3>'
- message: '<i class="fa fa-spinner fa-spin"></i> Calculating fee...</i>'
- buttons: [
- label: 'Send'
- cssClass: 'btn-primary'
- ,
- label: ' Cancel'
- cssClass: 'btn-default'
- action: (dialogItself) -> dialogItself.close()
- icon: 'glyphicon glyphicon-ban-circle'
- ]
- ).open()
-
- params =
- inputs: [{wallet_name: g.user.username, wallet_token: g.token}]
- outputs: [{addresses: [$('#recipient').val()], value: 1}]
- preference: $('#priority').val()
-
- $.post("#{g.api}/txs/new", JSON.stringify(params)).done((data) ->
- if $('#currency_toggle').html() is g.user.unit
- amount = $('#amount').val()
- else
- amount = convertedAmount()
-
- value = parseInt(amount * 100000000 / multiplier())
-
- params.fees = data.tx.fees
- params.outputs[0].value = value
- if value > parseFloat(g.balance).toSatoshis() - params.fees
- params.outputs[0].value -= params.fees
-
- $.post("#{g.api}/txs/new", JSON.stringify(params)).done((data) ->
- data.pubkeys = []
- if g.key instanceof bitcoin.ECPair
- data.signatures = data.tosign.map((tosign, i) ->
- data.pubkeys.push(g.key.getPublicKeyBuffer().toString('hex'))
- g.key.sign(new buffer.Buffer(tosign, "hex")).toDER().toString("hex")
- )
- else
- data.signatures = data.tosign.map((tosign, i) ->
- path = data.tx.inputs[i].hd_path.split('/')
- key = g.key.derive(parseInt(path[1])).derive(parseInt(path[2]))
- data.pubkeys.push(key.keyPair.getPublicKeyBuffer().toString('hex'))
- key.keyPair.sign(new buffer.Buffer(tosign, "hex")).toDER().toString("hex")
- )
-
- g.data = data
-
- amount = data.tx.outputs[0].value
- fee = data.tx.fees
- total = amount
- if value > parseFloat(g.balance).toSatoshis() - data.tx.fees
- total += fee
-
-
- $('.dialog .amount').html("#{(amount.toBTC())} #{g.user.unit} (#{amount.toFiat()} #{g.user.currency})")
- $('.dialog .fee').html("#{(fee.toBTC())} #{g.user.unit} (#{fee.toFiat()} #{g.user.currency})")
- $('.dialog .total').html("#{(total.toBTC())} #{g.user.unit} (#{total.toFiat()} #{g.user.currency})")
- $('.dialog .address').html(data.tx.outputs[0].addresses[0])
-
- dialog.getModalBody().html($('.dialog').html())
-
- if amount.toBTC() < 0.00000534
- displayErrors({errors: [error: 'Amount left over after fee is too small to send']}, dialog)
-
- dialog.getModal().find('.btn-primary').click(->
- $.post("#{g.api}/txs/send", JSON.stringify(g.data)).then((finaltx) ->
- $('#transaction_sent').fadeIn()
- balance = g.balance.toSatoshis() - finaltx.tx.outputs[0].value - finaltx.tx.fees
- g.balance = balance.toBTC()
- fiat = balance.toFiat()
- $('#balance').html(g.balance)
- $('#fiat').html("#{fiat} #{g.user.currency}")
- $('#blockchain').off('click').on('click', -> window.open('https://blockchain.info/tx/' + finaltx.tx.hash, '_blank'))
- dialog.close()
- )
- )
- ).fail((data) ->
- displayErrors(data.responseJSON, dialog)
- )
- ).fail((data) ->
- displayErrors(data.responseJSON, dialog)
- )
-
-displayErrors = (data, dialog) ->
- if data.errors
- dialog.getModalBody().html('')
- dialog.getModal().find('.btn-primary').hide()
- for e in data.errors
- dialog.getModalBody().append("<div class='alert alert-danger'>#{e.error}</div>")
-
-
-convertedAmount = ->
- g.amount = amount unless g.amount and !isNaN(parseFloat(g.amount))
- amount = parseFloat($('#amount').val() * multiplier() / g.exchange).toFixed(precision())
- difference = parseFloat(Math.abs(g.amount - amount).toFixed(precision()))
- tolerance = parseFloat((.00000002 * g.exchange * multiplier()).toFixed(precision()))
- if difference > tolerance
- return amount
- else
- return g.amount
-
-
-check_address = (address) ->
- try
- bitcoin.address.fromBase58Check(address)
- return true
- catch
- return isBip32(address)
-
-isBip32 = (address) ->
- try
- bitcoin.HDNode.fromBase58(address)
- return true
- catch
- return false
-
-multiplier = ->
- switch g.user.unit
- when 'BTC' then 1
- when 'mBTC' then 1000
- when 'µBTC' then 1000000
- when 'bits' then 1000000
- when 'satoshis' then 100000000
-
-precision = ->
- 9 - multiplier().toString().length
-
-Number.prototype.toBTC = ->
- parseFloat((this / 100000000 * multiplier())).toFixed(precision())
-
-Number.prototype.toFiat = ->
- parseFloat((this * g.exchange / 100000000)).toFixed(2)
-
-Number.prototype.toSatoshis = ->
- parseInt(this * 100000000 / multiplier())
-
-