Initial Commit.
This commit is contained in:
47
app.js
Normal file
47
app.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
var createError = require('http-errors');
|
||||||
|
var express = require('express');
|
||||||
|
var path = require('path');
|
||||||
|
var cookieParser = require('cookie-parser');
|
||||||
|
var logger = require('morgan');
|
||||||
|
|
||||||
|
var indexRouter = require('./routes/index');
|
||||||
|
var usersRouter = require('./routes/users');
|
||||||
|
var pgpRouter = require('./routes/pgp');
|
||||||
|
var walletRouter = require('./routes/wallet');
|
||||||
|
var transactionRouter = require('./routes/transaction');
|
||||||
|
|
||||||
|
var app = express();
|
||||||
|
|
||||||
|
// view engine setup
|
||||||
|
app.set('views', path.join(__dirname, 'views'));
|
||||||
|
app.set('view engine', 'ejs');
|
||||||
|
|
||||||
|
app.use(logger('dev'));
|
||||||
|
app.use(express.json());
|
||||||
|
app.use(express.urlencoded({ extended: false }));
|
||||||
|
app.use(cookieParser());
|
||||||
|
app.use(express.static(path.join(__dirname, 'public')));
|
||||||
|
|
||||||
|
app.use('/', indexRouter);
|
||||||
|
app.use('/users', usersRouter);
|
||||||
|
app.use('/pgp', pgpRouter);
|
||||||
|
app.use('/wallet', walletRouter);
|
||||||
|
app.use('/transaction', transactionRouter);
|
||||||
|
|
||||||
|
// catch 404 and forward to error handler
|
||||||
|
app.use(function(req, res, next) {
|
||||||
|
next(createError(404));
|
||||||
|
});
|
||||||
|
|
||||||
|
// error handler
|
||||||
|
app.use(function(err, req, res, next) {
|
||||||
|
// set locals, only providing error in development
|
||||||
|
res.locals.message = err.message;
|
||||||
|
res.locals.error = req.app.get('env') === 'development' ? err : {};
|
||||||
|
|
||||||
|
// render the error page
|
||||||
|
res.status(err.status || 500);
|
||||||
|
res.render('error');
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = app;
|
90
bin/www
Executable file
90
bin/www
Executable file
@ -0,0 +1,90 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var app = require('../app');
|
||||||
|
var debug = require('debug')('nodetest:server');
|
||||||
|
var http = require('http');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get port from environment and store in Express.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var port = normalizePort(process.env.PORT || '3000');
|
||||||
|
app.set('port', port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create HTTP server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var server = http.createServer(app);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen on provided port, on all network interfaces.
|
||||||
|
*/
|
||||||
|
|
||||||
|
server.listen(port);
|
||||||
|
server.on('error', onError);
|
||||||
|
server.on('listening', onListening);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize a port into a number, string, or false.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function normalizePort(val) {
|
||||||
|
var port = parseInt(val, 10);
|
||||||
|
|
||||||
|
if (isNaN(port)) {
|
||||||
|
// named pipe
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port >= 0) {
|
||||||
|
// port number
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event listener for HTTP server "error" event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onError(error) {
|
||||||
|
if (error.syscall !== 'listen') {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bind = typeof port === 'string'
|
||||||
|
? 'Pipe ' + port
|
||||||
|
: 'Port ' + port;
|
||||||
|
|
||||||
|
// handle specific listen errors with friendly messages
|
||||||
|
switch (error.code) {
|
||||||
|
case 'EACCES':
|
||||||
|
console.error(bind + ' requires elevated privileges');
|
||||||
|
process.exit(1);
|
||||||
|
break;
|
||||||
|
case 'EADDRINUSE':
|
||||||
|
console.error(bind + ' is already in use');
|
||||||
|
process.exit(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event listener for HTTP server "listening" event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onListening() {
|
||||||
|
var addr = server.address();
|
||||||
|
var bind = typeof addr === 'string'
|
||||||
|
? 'pipe ' + addr
|
||||||
|
: 'port ' + addr.port;
|
||||||
|
debug('Listening on ' + bind);
|
||||||
|
}
|
443
package-lock.json
generated
Normal file
443
package-lock.json
generated
Normal file
@ -0,0 +1,443 @@
|
|||||||
|
{
|
||||||
|
"name": "nodetest",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
|
"dependencies": {
|
||||||
|
"accepts": {
|
||||||
|
"version": "1.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
|
||||||
|
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
|
||||||
|
"requires": {
|
||||||
|
"mime-types": "~2.1.24",
|
||||||
|
"negotiator": "0.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"array-flatten": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||||
|
},
|
||||||
|
"asn1.js": {
|
||||||
|
"version": "5.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
|
||||||
|
"integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
|
||||||
|
"requires": {
|
||||||
|
"bn.js": "^4.0.0",
|
||||||
|
"inherits": "^2.0.1",
|
||||||
|
"minimalistic-assert": "^1.0.0",
|
||||||
|
"safer-buffer": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"basic-auth": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "5.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bn.js": {
|
||||||
|
"version": "4.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||||
|
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
|
||||||
|
},
|
||||||
|
"body-parser": {
|
||||||
|
"version": "1.18.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz",
|
||||||
|
"integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=",
|
||||||
|
"requires": {
|
||||||
|
"bytes": "3.0.0",
|
||||||
|
"content-type": "~1.0.4",
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"http-errors": "~1.6.3",
|
||||||
|
"iconv-lite": "0.4.23",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"qs": "6.5.2",
|
||||||
|
"raw-body": "2.3.3",
|
||||||
|
"type-is": "~1.6.16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bytes": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
|
||||||
|
},
|
||||||
|
"content-disposition": {
|
||||||
|
"version": "0.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
|
||||||
|
"integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
|
||||||
|
},
|
||||||
|
"content-type": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
|
||||||
|
},
|
||||||
|
"cookie": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
|
||||||
|
},
|
||||||
|
"cookie-parser": {
|
||||||
|
"version": "1.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz",
|
||||||
|
"integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==",
|
||||||
|
"requires": {
|
||||||
|
"cookie": "0.4.0",
|
||||||
|
"cookie-signature": "1.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cookie-signature": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
|
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
|
||||||
|
},
|
||||||
|
"crypto-js": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg=="
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"depd": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||||
|
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
|
||||||
|
},
|
||||||
|
"destroy": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
||||||
|
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
|
||||||
|
},
|
||||||
|
"ee-first": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
|
||||||
|
},
|
||||||
|
"ejs": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-PcW2a0tyTuPHz3tWyYqtK6r1fZ3gp+3Sop8Ph+ZYN81Ob5rwmbHEzaqs10N3BEsaGTkh/ooniXK+WwszGlc2+Q=="
|
||||||
|
},
|
||||||
|
"encodeurl": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
|
||||||
|
},
|
||||||
|
"escape-html": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
|
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
|
||||||
|
},
|
||||||
|
"etag": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||||
|
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
|
||||||
|
},
|
||||||
|
"express": {
|
||||||
|
"version": "4.16.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz",
|
||||||
|
"integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==",
|
||||||
|
"requires": {
|
||||||
|
"accepts": "~1.3.5",
|
||||||
|
"array-flatten": "1.1.1",
|
||||||
|
"body-parser": "1.18.3",
|
||||||
|
"content-disposition": "0.5.2",
|
||||||
|
"content-type": "~1.0.4",
|
||||||
|
"cookie": "0.3.1",
|
||||||
|
"cookie-signature": "1.0.6",
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"encodeurl": "~1.0.2",
|
||||||
|
"escape-html": "~1.0.3",
|
||||||
|
"etag": "~1.8.1",
|
||||||
|
"finalhandler": "1.1.1",
|
||||||
|
"fresh": "0.5.2",
|
||||||
|
"merge-descriptors": "1.0.1",
|
||||||
|
"methods": "~1.1.2",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"parseurl": "~1.3.2",
|
||||||
|
"path-to-regexp": "0.1.7",
|
||||||
|
"proxy-addr": "~2.0.4",
|
||||||
|
"qs": "6.5.2",
|
||||||
|
"range-parser": "~1.2.0",
|
||||||
|
"safe-buffer": "5.1.2",
|
||||||
|
"send": "0.16.2",
|
||||||
|
"serve-static": "1.13.2",
|
||||||
|
"setprototypeof": "1.1.0",
|
||||||
|
"statuses": "~1.4.0",
|
||||||
|
"type-is": "~1.6.16",
|
||||||
|
"utils-merge": "1.0.1",
|
||||||
|
"vary": "~1.1.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"cookie": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
|
||||||
|
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"finalhandler": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"encodeurl": "~1.0.2",
|
||||||
|
"escape-html": "~1.0.3",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"parseurl": "~1.3.2",
|
||||||
|
"statuses": "~1.4.0",
|
||||||
|
"unpipe": "~1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"forwarded": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
||||||
|
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
|
||||||
|
},
|
||||||
|
"fresh": {
|
||||||
|
"version": "0.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||||
|
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
|
||||||
|
},
|
||||||
|
"http-errors": {
|
||||||
|
"version": "1.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
|
||||||
|
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
|
||||||
|
"requires": {
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"inherits": "2.0.3",
|
||||||
|
"setprototypeof": "1.1.0",
|
||||||
|
"statuses": ">= 1.4.0 < 2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"iconv-lite": {
|
||||||
|
"version": "0.4.23",
|
||||||
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
|
||||||
|
"integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
|
||||||
|
"requires": {
|
||||||
|
"safer-buffer": ">= 2.1.2 < 3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"inherits": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||||
|
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||||
|
},
|
||||||
|
"ipaddr.js": {
|
||||||
|
"version": "1.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||||
|
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
|
||||||
|
},
|
||||||
|
"kyoto-tycoon": {
|
||||||
|
"version": "0.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/kyoto-tycoon/-/kyoto-tycoon-0.0.7.tgz",
|
||||||
|
"integrity": "sha1-gQlZ1+t0GiOtQa6YxMKlhBCpu7M="
|
||||||
|
},
|
||||||
|
"media-typer": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
|
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
||||||
|
},
|
||||||
|
"merge-descriptors": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
|
||||||
|
},
|
||||||
|
"methods": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||||
|
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
|
||||||
|
},
|
||||||
|
"mime": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
|
||||||
|
},
|
||||||
|
"mime-db": {
|
||||||
|
"version": "1.47.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz",
|
||||||
|
"integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw=="
|
||||||
|
},
|
||||||
|
"mime-types": {
|
||||||
|
"version": "2.1.30",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz",
|
||||||
|
"integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==",
|
||||||
|
"requires": {
|
||||||
|
"mime-db": "1.47.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimalistic-assert": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
|
||||||
|
},
|
||||||
|
"morgan": {
|
||||||
|
"version": "1.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz",
|
||||||
|
"integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==",
|
||||||
|
"requires": {
|
||||||
|
"basic-auth": "~2.0.0",
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"on-headers": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
|
},
|
||||||
|
"negotiator": {
|
||||||
|
"version": "0.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
||||||
|
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
|
||||||
|
},
|
||||||
|
"on-finished": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||||
|
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
|
||||||
|
"requires": {
|
||||||
|
"ee-first": "1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"on-headers": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
|
||||||
|
},
|
||||||
|
"openpgp": {
|
||||||
|
"version": "5.0.0-2",
|
||||||
|
"resolved": "https://registry.npmjs.org/openpgp/-/openpgp-5.0.0-2.tgz",
|
||||||
|
"integrity": "sha512-es+5A50Y+4JbtV+eugLPW9v/UkUIOufeOUyTcjbG8SMILNaLY9nEwUSJKDjQOadY+16w7Uqt0FDQ3Z1Vq7/F9g==",
|
||||||
|
"requires": {
|
||||||
|
"asn1.js": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parseurl": {
|
||||||
|
"version": "1.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||||
|
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
|
||||||
|
},
|
||||||
|
"path-to-regexp": {
|
||||||
|
"version": "0.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||||
|
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
|
||||||
|
},
|
||||||
|
"proxy-addr": {
|
||||||
|
"version": "2.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
|
||||||
|
"integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
|
||||||
|
"requires": {
|
||||||
|
"forwarded": "~0.1.2",
|
||||||
|
"ipaddr.js": "1.9.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"qs": {
|
||||||
|
"version": "6.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||||
|
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||||
|
},
|
||||||
|
"range-parser": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
|
||||||
|
},
|
||||||
|
"raw-body": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==",
|
||||||
|
"requires": {
|
||||||
|
"bytes": "3.0.0",
|
||||||
|
"http-errors": "1.6.3",
|
||||||
|
"iconv-lite": "0.4.23",
|
||||||
|
"unpipe": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
|
"safer-buffer": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
|
},
|
||||||
|
"send": {
|
||||||
|
"version": "0.16.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
|
||||||
|
"integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"destroy": "~1.0.4",
|
||||||
|
"encodeurl": "~1.0.2",
|
||||||
|
"escape-html": "~1.0.3",
|
||||||
|
"etag": "~1.8.1",
|
||||||
|
"fresh": "0.5.2",
|
||||||
|
"http-errors": "~1.6.2",
|
||||||
|
"mime": "1.4.1",
|
||||||
|
"ms": "2.0.0",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"range-parser": "~1.2.0",
|
||||||
|
"statuses": "~1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve-static": {
|
||||||
|
"version": "1.13.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
|
||||||
|
"integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
|
||||||
|
"requires": {
|
||||||
|
"encodeurl": "~1.0.2",
|
||||||
|
"escape-html": "~1.0.3",
|
||||||
|
"parseurl": "~1.3.2",
|
||||||
|
"send": "0.16.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"setprototypeof": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
|
||||||
|
},
|
||||||
|
"statuses": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
|
||||||
|
},
|
||||||
|
"type-is": {
|
||||||
|
"version": "1.6.18",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||||
|
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
||||||
|
"requires": {
|
||||||
|
"media-typer": "0.3.0",
|
||||||
|
"mime-types": "~2.1.24"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unpipe": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
||||||
|
},
|
||||||
|
"utils-merge": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
||||||
|
},
|
||||||
|
"vary": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
|
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
package.json
Normal file
19
package.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "toy-blockchain",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"start": "node ./bin/www"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"cookie-parser": "~1.4.4",
|
||||||
|
"crypto-js": "^4.0.0",
|
||||||
|
"debug": "~2.6.9",
|
||||||
|
"ejs": "~2.6.1",
|
||||||
|
"express": "~4.16.1",
|
||||||
|
"http-errors": "~1.6.3",
|
||||||
|
"kyoto-tycoon": "0.0.7",
|
||||||
|
"morgan": "~1.9.1",
|
||||||
|
"openpgp": "^5.0.0-2"
|
||||||
|
}
|
||||||
|
}
|
55
public/javascripts/dashboard.js
Normal file
55
public/javascripts/dashboard.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/* globals Chart:false, feather:false */
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
feather.replace()
|
||||||
|
|
||||||
|
// Graphs
|
||||||
|
var ctx = document.getElementById('myChart')
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
var myChart = new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: [
|
||||||
|
'Sunday',
|
||||||
|
'Monday',
|
||||||
|
'Tuesday',
|
||||||
|
'Wednesday',
|
||||||
|
'Thursday',
|
||||||
|
'Friday',
|
||||||
|
'Saturday'
|
||||||
|
],
|
||||||
|
datasets: [{
|
||||||
|
data: [
|
||||||
|
15339,
|
||||||
|
21345,
|
||||||
|
18483,
|
||||||
|
24003,
|
||||||
|
23489,
|
||||||
|
24092,
|
||||||
|
12034
|
||||||
|
],
|
||||||
|
lineTension: 0,
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
borderColor: '#007bff',
|
||||||
|
borderWidth: 4,
|
||||||
|
pointBackgroundColor: '#007bff'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
scales: {
|
||||||
|
yAxes: [{
|
||||||
|
ticks: {
|
||||||
|
beginAtZero: false
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
display: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})()
|
||||||
|
|
||||||
|
|
17
public/javascripts/openpgp.min.js
vendored
Normal file
17
public/javascripts/openpgp.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/javascripts/openpgp.min.js.map
Normal file
1
public/javascripts/openpgp.min.js.map
Normal file
File diff suppressed because one or more lines are too long
100
public/stylesheets/dashboard.css
Normal file
100
public/stylesheets/dashboard.css
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
body {
|
||||||
|
font-size: .875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feather {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Sidebar
|
||||||
|
**/
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
/* rtl:raw:
|
||||||
|
* right: 0;
|
||||||
|
**/
|
||||||
|
bottom: 0;
|
||||||
|
/* rtl:remove */
|
||||||
|
left: 0;
|
||||||
|
z-index: 100; /* Behind the navbar */
|
||||||
|
padding: 48px 0 0; /* Height of navbar */
|
||||||
|
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767.98px) {
|
||||||
|
.sidebar {
|
||||||
|
top: 5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-sticky {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
height: calc(100vh - 48px);
|
||||||
|
padding-top: .5rem;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .nav-link {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .nav-link .feather {
|
||||||
|
margin-right: 4px;
|
||||||
|
color: #727272;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .nav-link.active {
|
||||||
|
color: #007bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .nav-link:hover .feather,
|
||||||
|
.sidebar .nav-link.active .feather {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-heading {
|
||||||
|
font-size: .75rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* * Navbar
|
||||||
|
* */
|
||||||
|
|
||||||
|
.navbar-brand {
|
||||||
|
padding-top: .75rem;
|
||||||
|
padding-bottom: .75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
background-color: rgba(0, 0, 0, .25);
|
||||||
|
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar .navbar-toggler {
|
||||||
|
top: .25rem;
|
||||||
|
right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar .form-control {
|
||||||
|
padding: .75rem 1rem;
|
||||||
|
border-width: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-dark {
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgba(255, 255, 255, .1);
|
||||||
|
border-color: rgba(255, 255, 255, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-dark:focus {
|
||||||
|
border-color: transparent;
|
||||||
|
box-shadow: 0 0 0 3px rgba(255, 255, 255, .25);
|
||||||
|
}
|
8
public/stylesheets/style.css
Normal file
8
public/stylesheets/style.css
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
body {
|
||||||
|
padding: 50px;
|
||||||
|
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #00B7FF;
|
||||||
|
}
|
165
routes/index.js
Normal file
165
routes/index.js
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
var express = require('express');
|
||||||
|
var router = express.Router();
|
||||||
|
var KyotoTycoon = require('kyoto-tycoon').KyotoTycoon;
|
||||||
|
|
||||||
|
var CryptoJS = require('crypto-js');
|
||||||
|
|
||||||
|
var kt = new KyotoTycoon();
|
||||||
|
|
||||||
|
function randomString(length) {
|
||||||
|
chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
|
var result = '';
|
||||||
|
for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mineBlock(block, requirement) {
|
||||||
|
rand = '';
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
while(CryptoJS.SHA512(JSON.stringify(block.content)).toString().substring(0, requirement.length) != requirement) {
|
||||||
|
rand = randomString(32);
|
||||||
|
block.content.rand = rand;
|
||||||
|
i++;
|
||||||
|
console.log(i + ': ' + rand + ' : ' + CryptoJS.SHA512(JSON.stringify(block.content)).toString());
|
||||||
|
}
|
||||||
|
block.hash = CryptoJS.SHA512(JSON.stringify(block.content)).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkBlock(id, badId, goodId) {
|
||||||
|
kt.get(id, function(err, data) {
|
||||||
|
if(err) {
|
||||||
|
console.log('Error getting block id ' + id);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
kt.get(id - 1, function(err, prevData){
|
||||||
|
if(err) {
|
||||||
|
console.log('Error getting block id ' + id - 1);
|
||||||
|
}
|
||||||
|
block = JSON.parse(data);
|
||||||
|
if((CryptoJS.SHA512(JSON.stringify(block.content)).toString() === block.hash) && (block.content.prevhash === JSON.parse(prevData).hash)) {
|
||||||
|
console.log('Block ' + block.content.id + ' is OK');
|
||||||
|
if(goodId) {
|
||||||
|
goodId(block.content.id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Block ' + block.content.id + ' is bad');
|
||||||
|
if(badId) {
|
||||||
|
badId(block.content.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkChain() {
|
||||||
|
j = 0;
|
||||||
|
kt.status(':', async function (err, data) {
|
||||||
|
if(err) {
|
||||||
|
console.log('Error getting chain data.');
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
for(i = 1; i < data.count; i++) {
|
||||||
|
await checkBlock(i, function(id) {
|
||||||
|
console.log('Handle badId: ' + id);
|
||||||
|
deleteChain(id, data.count - 1);
|
||||||
|
}, function(id) {
|
||||||
|
console.log('Handle goodId: ' + id)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteChain(firstId, lastId) {
|
||||||
|
for(i = firstId; i <= lastId; i++) {
|
||||||
|
console.log('Deleteing block id ' + i);
|
||||||
|
kt.remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLastTransactions(count, next) {
|
||||||
|
result = [];
|
||||||
|
j = 0;
|
||||||
|
kt.status(':', async function(err, data) {
|
||||||
|
if(err) {
|
||||||
|
console.log('Error getting chain data.');
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for(i = data.count - count; i < data.count; i++) {
|
||||||
|
result.push(new Promise((resolve, reject) => {
|
||||||
|
kt.get(i, async function(err, block) {
|
||||||
|
if(err) reject(err);
|
||||||
|
resolve(JSON.parse(block));
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if(next) {
|
||||||
|
next(await Promise.all(result));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GET home page. */
|
||||||
|
router.get('/', function(req, res, next) {
|
||||||
|
getLastTransactions(15, async function(data) {
|
||||||
|
await console.log(JSON.stringify(data));
|
||||||
|
breadcrumb = [{title:'home', url:'/', stat:'active'}]
|
||||||
|
await res.render('index', { title: 'mCoin', data: data, breadcrumb: breadcrumb });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/new', function(req, res, next) {
|
||||||
|
block = {
|
||||||
|
content: {
|
||||||
|
message: {
|
||||||
|
from: 'Simona',
|
||||||
|
to: 'Matjaz',
|
||||||
|
amount: '200',
|
||||||
|
timestamp: '1234',
|
||||||
|
},
|
||||||
|
id: 1,
|
||||||
|
previd: 0,
|
||||||
|
prevhash: 'abc',
|
||||||
|
rand: '',
|
||||||
|
timestamp: '',
|
||||||
|
unixtime: '',
|
||||||
|
},
|
||||||
|
hash: '',
|
||||||
|
difficulty: '',
|
||||||
|
version: '0.01',
|
||||||
|
};
|
||||||
|
difficulty = '000';
|
||||||
|
|
||||||
|
kt.status(':', function(err, data) {
|
||||||
|
if(err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
kt.get(data.count - 1, function(err, prevData) {
|
||||||
|
if(err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
const utcDate = new Date();
|
||||||
|
block.content.timestamp = utcDate.toUTCString();
|
||||||
|
block.content.unixtime = Math.floor(new Date().getTime() / 1000);
|
||||||
|
block.content.prevhash = JSON.parse(prevData).hash;
|
||||||
|
block.content.id = data.count;
|
||||||
|
block.content.previd = data.count - 1;
|
||||||
|
block.difficulty = difficulty;
|
||||||
|
mineBlock(block, difficulty);
|
||||||
|
console.log(JSON.stringify(block));
|
||||||
|
kt.set(block.content.id.toString(), JSON.stringify(block), function() {
|
||||||
|
console.log('Block Written');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/check', function(req, res, next) {
|
||||||
|
badBlock = 0;
|
||||||
|
console.log('Checking the chain');
|
||||||
|
checkChain();
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
26
routes/pgp.js
Normal file
26
routes/pgp.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
var express = require('express');
|
||||||
|
var router = express.Router();
|
||||||
|
|
||||||
|
const openpgp = require('openpgp');
|
||||||
|
|
||||||
|
router.get('/', function(req, res, next) {
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const { privateKeyArmored, publicKeyArmored, revocationCertificate } = await openpgp.generateKey({
|
||||||
|
type: 'ecc', // Type of the key, defaults to ECC
|
||||||
|
curve: 'curve25519', // ECC curve name, defaults to curve25519
|
||||||
|
userIDs: [{ name: 'Jon Doe', email: 'jon@doe.com' }], // you can pass multiple user IDs
|
||||||
|
passphrase: 'super long and hard to guess secret' // protects the private key
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(privateKeyArmored); // '-----BEGIN PGP PRIVATE KEY BLOCK ... '
|
||||||
|
console.log(publicKeyArmored); // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
|
||||||
|
console.log(revocationCertificate); // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
res.send('respond with a resource');
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
10
routes/transaction.js
Normal file
10
routes/transaction.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
var express = require('express');
|
||||||
|
var router = express.Router();
|
||||||
|
|
||||||
|
/* GET users listing. */
|
||||||
|
router.get('/', function(req, res, next) {
|
||||||
|
breadcrumb = [{title:'home', url:'/', stat:''}, {title:'transaction', url:'/transaction', stat:'active'}];
|
||||||
|
res.render('transaction', {title: 'Transaction', breadcrumb: breadcrumb});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
9
routes/users.js
Normal file
9
routes/users.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
var express = require('express');
|
||||||
|
var router = express.Router();
|
||||||
|
|
||||||
|
/* GET users listing. */
|
||||||
|
router.get('/', function(req, res, next) {
|
||||||
|
res.send('respond with a resource');
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
20
routes/wallet.js
Normal file
20
routes/wallet.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
var express = require('express');
|
||||||
|
var router = express.Router();
|
||||||
|
|
||||||
|
/* GET users listing. */
|
||||||
|
router.get('/', function(req, res, next) {
|
||||||
|
breadcrumb = [{title:'home', url:'/', stat:''}, {title:'wallet', url:'/wallet', stat:'active'}];
|
||||||
|
res.render('wallet', {title: 'Wallet Management', breadcrumb: breadcrumb});
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/new', function(req, res, next) {
|
||||||
|
breadcrumb = [{title: 'home', url: '/', stat: ''}, {title: 'wallet', url:'/wallet', stat: ''}, {title:'new wallet', url:'/wallet/new', stat:'active'}];
|
||||||
|
res.render('new-wallet', {title: 'Create New Wallet', breadcrumb: breadcrumb});
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/open', function(req, res, next) {
|
||||||
|
breadcrumb = [{title: 'home', url: '/', stat: ''}, {title: 'wallet', url:'/wallet', stat: ''}, {title:'open wallet', url:'/wallet/open', stat:'active'}];
|
||||||
|
res.render('open-wallet', {title: 'Open Wallet', breadcrumb: breadcrumb});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
21
views/breadcrumb.ejs
Normal file
21
views/breadcrumb.ejs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3">
|
||||||
|
<nav aria-label="breadcrumb">
|
||||||
|
<ol class="breadcrumb" id="breadcrumb-id">
|
||||||
|
<% breadcrumb.forEach(function(crumb) { %>
|
||||||
|
|
||||||
|
<li class="breadcrumb-item
|
||||||
|
<% if(crumb.stat === 'active') { %>
|
||||||
|
|
||||||
|
active" aria-current="page"><%- crumb.title%>
|
||||||
|
|
||||||
|
<% } else {%>
|
||||||
|
|
||||||
|
"><a href="<%- crumb.url %>"><%- crumb.title%></a>
|
||||||
|
|
||||||
|
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<% }}) %>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
</div>
|
3
views/error.ejs
Normal file
3
views/error.ejs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<h1><%= message %></h1>
|
||||||
|
<h2><%= error.status %></h2>
|
||||||
|
<pre><%= error.stack %></pre>
|
129
views/footer.ejs
Normal file
129
views/footer.ejs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<!-- Footer -->
|
||||||
|
<footer
|
||||||
|
class="text-center text-lg-start text-white"
|
||||||
|
style="background-color: #1c2331"
|
||||||
|
>
|
||||||
|
<!-- Section: Social media -->
|
||||||
|
<section
|
||||||
|
class="d-flex justify-content-between p-4"
|
||||||
|
style="background-color: #6351ce"
|
||||||
|
>
|
||||||
|
<!-- Left -->
|
||||||
|
<div class="me-5">
|
||||||
|
<span>Get connected with us on social networks:</span>
|
||||||
|
</div>
|
||||||
|
<!-- Left -->
|
||||||
|
|
||||||
|
<!-- Right -->
|
||||||
|
<div>
|
||||||
|
<a href="" class="text-white me-4"><i class="fab fa-facebook-f"></i></a>
|
||||||
|
<a href="" class="text-white me-4"><i class="fab fa-twitter"></i></a>
|
||||||
|
<a href="" class="text-white me-4"><i class="fab fa-google"></i></a>
|
||||||
|
<a href="" class="text-white me-4"><i class="fab fa-instagram"></i></a>
|
||||||
|
<a href="" class="text-white me-4"><i class="fab fa-linkedin"></i></a>
|
||||||
|
<a href="" class="text-white me-4"><i class="fab fa-github"></i></a>
|
||||||
|
</div>
|
||||||
|
<!-- Right -->
|
||||||
|
</section>
|
||||||
|
<!-- Section: Social media -->
|
||||||
|
|
||||||
|
<!-- Section: Links -->
|
||||||
|
<section class="">
|
||||||
|
<div class="container text-center text-md-start mt-5">
|
||||||
|
<!-- Grid row -->
|
||||||
|
<div class="row mt-3">
|
||||||
|
<!-- Grid column -->
|
||||||
|
<div class="col-md-3 col-lg-4 col-xl-3 mx-auto mb-4">
|
||||||
|
<!-- Content -->
|
||||||
|
<h6 class="text-uppercase fw-bold">Company name</h6>
|
||||||
|
<hr
|
||||||
|
class="mb-4 mt-0 d-inline-block mx-auto"
|
||||||
|
style="width: 60px; background-color: #7c4dff; height: 2px"
|
||||||
|
/>
|
||||||
|
<p>
|
||||||
|
Here you can use rows and columns to organize your footer
|
||||||
|
content. Lorem ipsum dolor sit amet, consectetur adipisicing
|
||||||
|
elit.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<!-- Grid column -->
|
||||||
|
|
||||||
|
<!-- Grid column -->
|
||||||
|
<div class="col-md-2 col-lg-2 col-xl-2 mx-auto mb-4">
|
||||||
|
<!-- Links -->
|
||||||
|
<h6 class="text-uppercase fw-bold">Products</h6>
|
||||||
|
<hr
|
||||||
|
class="mb-4 mt-0 d-inline-block mx-auto"
|
||||||
|
style="width: 60px; background-color: #7c4dff; height: 2px"
|
||||||
|
/>
|
||||||
|
<p>
|
||||||
|
<a href="#!" class="text-white">MDBootstrap</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="#!" class="text-white">MDWordPress</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="#!" class="text-white">BrandFlow</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="#!" class="text-white">Bootstrap Angular</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<!-- Grid column -->
|
||||||
|
|
||||||
|
<!-- Grid column -->
|
||||||
|
<div class="col-md-3 col-lg-2 col-xl-2 mx-auto mb-4">
|
||||||
|
<!-- Links -->
|
||||||
|
<h6 class="text-uppercase fw-bold">Useful links</h6>
|
||||||
|
<hr
|
||||||
|
class="mb-4 mt-0 d-inline-block mx-auto"
|
||||||
|
style="width: 60px; background-color: #7c4dff; height: 2px"
|
||||||
|
/>
|
||||||
|
<p>
|
||||||
|
<a href="#!" class="text-white">Your Account</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="#!" class="text-white">Become an Affiliate</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="#!" class="text-white">Shipping Rates</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="#!" class="text-white">Help</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<!-- Grid column -->
|
||||||
|
|
||||||
|
<!-- Grid column -->
|
||||||
|
<div class="col-md-4 col-lg-3 col-xl-3 mx-auto mb-md-0 mb-4">
|
||||||
|
<!-- Links -->
|
||||||
|
<h6 class="text-uppercase fw-bold">Contact</h6>
|
||||||
|
<hr
|
||||||
|
class="mb-4 mt-0 d-inline-block mx-auto"
|
||||||
|
style="width: 60px; background-color: #7c4dff; height: 2px"
|
||||||
|
/>
|
||||||
|
<p><i class="fas fa-home mr-3"></i> New York, NY 10012, US</p>
|
||||||
|
<p><i class="fas fa-envelope mr-3"></i> info@example.com</p>
|
||||||
|
<p><i class="fas fa-phone mr-3"></i> + 01 234 567 88</p>
|
||||||
|
<p><i class="fas fa-print mr-3"></i> + 01 234 567 89</p>
|
||||||
|
</div>
|
||||||
|
<!-- Grid column -->
|
||||||
|
</div>
|
||||||
|
<!-- Grid row -->
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- Section: Links -->
|
||||||
|
|
||||||
|
<!-- Copyright -->
|
||||||
|
<div
|
||||||
|
class="text-center p-3"
|
||||||
|
style="background-color: rgba(0, 0, 0, 0.2)"
|
||||||
|
>
|
||||||
|
© 2020 Copyright:
|
||||||
|
<a class="text-white" href="https://mdbootstrap.com/"
|
||||||
|
>MDBootstrap.com</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<!-- Copyright -->
|
||||||
|
</footer>
|
||||||
|
<!-- Footer -->
|
12
views/header.ejs
Normal file
12
views/header.ejs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<header class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
|
||||||
|
<a class="navbar-brand col-md-3 col-lg-2 me-0 px-3" href="/">mCoin</a>
|
||||||
|
<button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
|
||||||
|
<ul class="navbar-nav px-3">
|
||||||
|
<li class="nav-item text-nowrap">
|
||||||
|
<a class="nav-link" href="#">Sign out</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</header>
|
69
views/index.ejs
Normal file
69
views/index.ejs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title><%= title %></title>
|
||||||
|
<!--<link rel='stylesheet' href='/stylesheets/style.css' />-->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
|
||||||
|
<meta name="theme-color" content="#7952b3">
|
||||||
|
<link href="/stylesheets/dashboard.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%- include('header.ejs') %>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<%- include('sidebar.ejs') %>
|
||||||
|
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
|
||||||
|
<%- include('breadcrumb.ejs', {breadcrumb: breadcrumb}) %>
|
||||||
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
|
<h1 class="h2">Dashboard</h1>
|
||||||
|
<div class="btn-toolbar mb-2 mb-md-0">
|
||||||
|
<div class="btn-group me-2">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary">Share</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary">Export</button>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle">
|
||||||
|
<span data-feather="calendar"></span>
|
||||||
|
This week
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<canvas class="my-4 w-100" id="myChart" width="900" height="380"></canvas>
|
||||||
|
|
||||||
|
<h2><%= title %></h2>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-sm">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>From</th>
|
||||||
|
<th>To</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
<th>Block Timestamp</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% data.forEach(function(block) {%>
|
||||||
|
<tr>
|
||||||
|
<td><%= block.content.id %></td>
|
||||||
|
<td><%= block.content.message.from %></td>
|
||||||
|
<td><%= block.content.message.to %></td>
|
||||||
|
<td><%= block.content.message.amount %> mCoins</td>
|
||||||
|
<td><%= block.content.timestamp %></td>
|
||||||
|
</tr>
|
||||||
|
<%}); %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<%- include('footer.ejs') %>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/feather.min.js" integrity="sha384-uO3SXW5IuS1ZpFPKugNNWqTZRRglnUJK6UAZ/gxOX80nxEkN9NcGZTftn6RzhGWE" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js" integrity="sha384-zNy6FEbO50N+Cg5wap8IKA4M/ZnLJgzc6w2NqACZaK0u0FXfOWRRJOnQtpZun8ha" crossorigin="anonymous"></script><script src="/javascripts/dashboard.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
21
views/navbar.ejs
Normal file
21
views/navbar.ejs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<nav class="navbar navbar-expand-lg navbar-light" style="background-color: #e3f2fd;">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="/">mCoin</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" aria-current="page" href="#">Home</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">Features</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">Pricing</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
118
views/new-wallet.ejs
Normal file
118
views/new-wallet.ejs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title><%= title %></title>
|
||||||
|
<!--<link rel='stylesheet' href='/stylesheets/style.css' />-->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
|
||||||
|
<meta name="theme-color" content="#7952b3">
|
||||||
|
<link href="/stylesheets/dashboard.css" rel="stylesheet">
|
||||||
|
<script>
|
||||||
|
function uuidv4() {
|
||||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||||
|
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||||
|
return v.toString(16);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="generateWallet()">
|
||||||
|
<%- include('header.ejs') %>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<%- include('sidebar.ejs') %>
|
||||||
|
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
|
||||||
|
<%- include('breadcrumb.ejs', {breadcrumb: breadcrumb}) %>
|
||||||
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
|
<h2><%= title %></h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form class="row g-3">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="wallet-id" class="form-label">Wallet ID</label>
|
||||||
|
<input type="email" readonly class="form-control-plaintext" id="wallet-id" placeholder="id@uplink.si">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="private-key-id" class="form-label">Private Key</label>
|
||||||
|
<textarea class="form-control-plaintext" readonly id="private-key-id" rows="5"></textarea>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="public-key-id" class="form-label">Public Key</label>
|
||||||
|
<textarea class="form-control-plaintext" readonly id="public-key-id" rows="5"></textarea>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button onclick="getFingerprintM()" type="button" class="btn btn-primary">Fingerprint</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="fingerprint-id" class="form-label">Fingerprint</label>
|
||||||
|
<input class="form-control-plaintext" readonly id="fingerprint-id"></input>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button onclick="saveKey()" type="button" class="btn btn-primary">Save Key</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
function generateWallet() {
|
||||||
|
document.getElementById('wallet-id').value = uuidv4() + '@uplink.si';
|
||||||
|
generateKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
publicKey;
|
||||||
|
|
||||||
|
function generateKeys() {
|
||||||
|
(async () => {
|
||||||
|
const { privateKeyArmored, publicKeyArmored, revoationCertificate } = await openpgp.generateKey({
|
||||||
|
type: 'ecc', // Type of the key, defaults to ECC
|
||||||
|
curve: 'curve25519', // ECC curve name, defaults to curve25519
|
||||||
|
userIDs: [{ name: '', email: document.getElementById('wallet-id').value }], // you can pass multiple user IDs
|
||||||
|
passphrase: 'super long and hard to guess secret' // protects the private key
|
||||||
|
});
|
||||||
|
document.getElementById('private-key-id').value = privateKeyArmored;
|
||||||
|
document.getElementById('public-key-id').value = publicKeyArmored;
|
||||||
|
//console.log(privateKeyArmored); // '-----BEGIN PGP PRIVATE KEY BLOCK ... '
|
||||||
|
//console.log(publicKeyArmored); // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
|
||||||
|
//console.log(revocationCertificate); // '-----BEGIN PGP PUBLIC KEY BLOCK ... '
|
||||||
|
publicKey = await openpgp.readKey({armoredKey: publicKeyArmored});
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFingerprintM() {
|
||||||
|
document.getElementById('fingerprint-id').value = publicKey.getFingerprint();
|
||||||
|
}
|
||||||
|
|
||||||
|
function download(filename, text) {
|
||||||
|
var element = document.createElement('a');
|
||||||
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
||||||
|
element.setAttribute('download', filename);
|
||||||
|
element.style.display = 'none';
|
||||||
|
document.body.appendChild(element);
|
||||||
|
element.click();
|
||||||
|
document.body.removeChild(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveKey() {
|
||||||
|
key = {};
|
||||||
|
key.privateKey = document.getElementById('private-key-id').value;
|
||||||
|
key.publicKey = document.getElementById('public-key-id').value;
|
||||||
|
key.fingerprint = document.getElementById('fingerprint-id').value;
|
||||||
|
key.user = document.getElementById('wallet-id').value;
|
||||||
|
download('key.txt',JSON.stringify(key));
|
||||||
|
|
||||||
|
if(typeof(Storage) !== "undefined") {
|
||||||
|
localStorage.setItem('privateKey', key.privateKey);
|
||||||
|
localStorage.setItem('publicKey', key.publicKey);
|
||||||
|
localStorage.setItem('fingerprint', key.fingerprint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<script src="/javascripts/openpgp.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/feather.min.js" integrity="sha384-uO3SXW5IuS1ZpFPKugNNWqTZRRglnUJK6UAZ/gxOX80nxEkN9NcGZTftn6RzhGWE" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js" integrity="sha384-zNy6FEbO50N+Cg5wap8IKA4M/ZnLJgzc6w2NqACZaK0u0FXfOWRRJOnQtpZun8ha" crossorigin="anonymous"></script><script src="/javascripts/dashboard.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
88
views/open-wallet.ejs
Normal file
88
views/open-wallet.ejs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title><%= title %></title>
|
||||||
|
<!--<link rel='stylesheet' href='/stylesheets/style.css' />-->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
|
||||||
|
<meta name="theme-color" content="#7952b3">
|
||||||
|
<link href="/stylesheets/dashboard.css" rel="stylesheet">
|
||||||
|
<script>
|
||||||
|
function uuidv4() {
|
||||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||||
|
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||||
|
return v.toString(16);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%- include('header.ejs') %>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<%- include('sidebar.ejs') %>
|
||||||
|
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
|
||||||
|
<%- include('breadcrumb.ejs', {breadcrumb: breadcrumb}) %>
|
||||||
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
|
<h2><%= title %></h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form class="row g-3">
|
||||||
|
<div>
|
||||||
|
<label for="file-selector-id" class="form-label">Open Key</label>
|
||||||
|
<input class="form-control" type="file" id="file-selector-id" multiple>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button onclick="openKey()" type="button" class="btn btn-primary">Open Key</button>
|
||||||
|
</div>
|
||||||
|
<div id="alert">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
myKey = {};
|
||||||
|
const fileSelector = document.getElementById('file-selector-id');
|
||||||
|
fileSelector.addEventListener('change', (event) => {
|
||||||
|
const fileList = event.target.files;
|
||||||
|
console.log(fileList);
|
||||||
|
readKeyFile(fileList[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
function readKeyFile(file) {
|
||||||
|
if(file.type && !file.type.startsWith('text/')) {
|
||||||
|
console.log('File is not a text file');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.addEventListener('load', (event) => {
|
||||||
|
key = event.target.result;
|
||||||
|
console.log(key);
|
||||||
|
myKey = JSON.parse(key);
|
||||||
|
});
|
||||||
|
reader.readAsText(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openKey() {
|
||||||
|
if(typeof(Storage) !== 'undefined') {
|
||||||
|
localStorage.setItem('privateKey', myKey.privateKey);
|
||||||
|
localStorage.setItem('publicKey', myKey.publicKey);
|
||||||
|
localStorage.setItem('fingerprint', myKey.fingerprint);
|
||||||
|
if(localStorage.getItem('fingerprint') !== 'undefined') {
|
||||||
|
document.getElementById('alert').innerHTML = '<div class="alert alert-success" role="alert">Key opened successfully. Fingerprint: ' + localStorage.getItem('fingerprint') + '</div>';
|
||||||
|
} else {
|
||||||
|
document.getElementById('alert').innerHTML = '<div class="alert alert-danger" role="alert">Key not opened. Try again.</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<script src="/javascripts/openpgp.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/feather.min.js" integrity="sha384-uO3SXW5IuS1ZpFPKugNNWqTZRRglnUJK6UAZ/gxOX80nxEkN9NcGZTftn6RzhGWE" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js" integrity="sha384-zNy6FEbO50N+Cg5wap8IKA4M/ZnLJgzc6w2NqACZaK0u0FXfOWRRJOnQtpZun8ha" crossorigin="anonymous"></script><script src="/javascripts/dashboard.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
76
views/sidebar.ejs
Normal file
76
views/sidebar.ejs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse">
|
||||||
|
<div class="position-sticky pt-3">
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" aria-current="page" href="/">
|
||||||
|
<span data-feather="home"></span>
|
||||||
|
Dashboard
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/wallet">
|
||||||
|
<span data-feather="book"></span>
|
||||||
|
Wallet
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/transaction">
|
||||||
|
<span data-feather="zap"></span>
|
||||||
|
Transaction
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">
|
||||||
|
<span data-feather="users"></span>
|
||||||
|
Customers
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">
|
||||||
|
<span data-feather="bar-chart-2"></span>
|
||||||
|
Reports
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">
|
||||||
|
<span data-feather="layers"></span>
|
||||||
|
Integrations
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||||
|
<span>Saved reports</span>
|
||||||
|
<a class="link-secondary" href="#" aria-label="Add a new report">
|
||||||
|
<span data-feather="plus-circle"></span>
|
||||||
|
</a>
|
||||||
|
</h6>
|
||||||
|
<ul class="nav flex-column mb-2">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">
|
||||||
|
<span data-feather="file-text"></span>
|
||||||
|
Current month
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">
|
||||||
|
<span data-feather="file-text"></span>
|
||||||
|
Last quarter
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">
|
||||||
|
<span data-feather="file-text"></span>
|
||||||
|
Social engagement
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">
|
||||||
|
<span data-feather="file-text"></span>
|
||||||
|
Year-end sale
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
148
views/transaction.ejs
Normal file
148
views/transaction.ejs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title><%= title %></title>
|
||||||
|
<!--<link rel='stylesheet' href='/stylesheets/style.css' />-->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
|
||||||
|
<meta name="theme-color" content="#7952b3">
|
||||||
|
<link href="/stylesheets/dashboard.css" rel="stylesheet">
|
||||||
|
<script>
|
||||||
|
function uuidv4() {
|
||||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||||
|
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||||
|
return v.toString(16);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%- include('header.ejs') %>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<%- include('sidebar.ejs') %>
|
||||||
|
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
|
||||||
|
<%- include('breadcrumb.ejs', {breadcrumb:breadcrumb}) %>
|
||||||
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
|
<h2><%= title %></h2>
|
||||||
|
</div>
|
||||||
|
<form class="row g-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-text" id="basic-addon">From</span>
|
||||||
|
<input type="text" class="form-control" id="from-id">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-text" id="basic-addon">To</span>
|
||||||
|
<input type="text" class="form-control" id="to-id">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-text" id="basic-addon">Amount</span>
|
||||||
|
<input type="" class="form-control" id="amount-id">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button type="button" class="btn btn-primary btn-lg">Send</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="message-id" class="form-label">Plaintext Message</label>
|
||||||
|
<textarea class="form-control" id="message-id" rows="5"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="private-key-id" class="form-label">Private Key</label>
|
||||||
|
<textarea class="form-control" id="private-key-id" rows="5"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<button type="button" class="btn btn-primary col-auto" onclick="signMessageA()">Sign Message</button>
|
||||||
|
<button type="button" class="btn btn-primary col-auto">Primary</button>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="signed-message-id" class="form-label">Signed Message</label>
|
||||||
|
<textarea class="form-control" id="signed-message-id" rows="5"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="public-key-id" class="form-label">Public Key</label>
|
||||||
|
<textarea class="form-control" id="public-key-id" rows="5"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<button type="button" class="btn btn-primary col-auto" onclick="verifySig()">Verify Message</button>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
const passphrase = 'super long and hard to guess secret';
|
||||||
|
var privateKey;
|
||||||
|
var privateKeyxx;
|
||||||
|
var unsignedMessageM;
|
||||||
|
|
||||||
|
async function signMessage0() {
|
||||||
|
privateKeyxx = await openpgp.readKey({ armoredKey: document.getElementById('private-key-id').value });
|
||||||
|
console.log('readKey done');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function signMessage1() {
|
||||||
|
privateKey = await openpgp.decryptKey({
|
||||||
|
privateKey: privateKeyxx,
|
||||||
|
passphrase
|
||||||
|
});
|
||||||
|
console.log('decryptKey done');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function signMessage2() {
|
||||||
|
unsignedMessageM = await openpgp.createCleartextMessage({ text: document.getElementById('message-id').value });
|
||||||
|
console.log('createCleartextMessage done');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function signMessage3() {
|
||||||
|
document.getElementById('signed-message-id').value = await openpgp.sign({
|
||||||
|
message: unsignedMessageM, // CleartextMessage or Message object
|
||||||
|
privateKeys: privateKey, // for signing
|
||||||
|
detached: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function signMessageA() {
|
||||||
|
await signMessage0();
|
||||||
|
await signMessage1();
|
||||||
|
await signMessage2();
|
||||||
|
await signMessage3();
|
||||||
|
}
|
||||||
|
|
||||||
|
var signedMessage2;
|
||||||
|
var publicKey;
|
||||||
|
var verified;
|
||||||
|
|
||||||
|
async function verify0() {
|
||||||
|
signedMessage2 = await openpgp.readCleartextMessage({cleartextMessage: document.getElementById('signed-message-id').value});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verify1() {
|
||||||
|
publicKey = await openpgp.readKey({armoredKey: document.getElementById('public-key-id').value});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verify2() {
|
||||||
|
verified = await openpgp.verify({message: signedMessage2, publicKeys: publicKey});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verifySig() {
|
||||||
|
await verify0();
|
||||||
|
await verify1();
|
||||||
|
await verify2();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<script src="/javascripts/openpgp.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/feather.min.js" integrity="sha384-uO3SXW5IuS1ZpFPKugNNWqTZRRglnUJK6UAZ/gxOX80nxEkN9NcGZTftn6RzhGWE" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js" integrity="sha384-zNy6FEbO50N+Cg5wap8IKA4M/ZnLJgzc6w2NqACZaK0u0FXfOWRRJOnQtpZun8ha" crossorigin="anonymous"></script><script src="/javascripts/dashboard.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
62
views/wallet.ejs
Normal file
62
views/wallet.ejs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title><%= title %></title>
|
||||||
|
<!--<link rel='stylesheet' href='/stylesheets/style.css' />-->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
|
||||||
|
<meta name="theme-color" content="#7952b3">
|
||||||
|
<link href="/stylesheets/dashboard.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%- include('header.ejs') %>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<%- include('sidebar.ejs') %>
|
||||||
|
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
|
||||||
|
<%- include('breadcrumb.ejs', {breadcrumb: breadcrumb}) %>
|
||||||
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
|
<h2><%= title %></h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="card-group">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">New Wallet</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Create a New Wallet</h5>
|
||||||
|
<p class="card-text">If you do not already have a wallet, you can create a new one!</p>
|
||||||
|
<p class="card-text">Process of creation of new wallet is simple. Just visit the link below and a new wallet will be generated for you. You can then save it to jour computer and use it next time you visit this page.</p>
|
||||||
|
<p><a href="/wallet/new">New Wallet</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Open Wallet</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Use Existing Wallet</h5>
|
||||||
|
<p class="card-text">If you already have a wallet, it is easy to open it.</p>
|
||||||
|
<p class="card-text">Visit link below to open your wallet file. It is easy and secure.</p>
|
||||||
|
<p><a href="/wallet/open">Open Wallet</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Bring Your Own</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Create Your Own Wallet</h5>
|
||||||
|
<p class="card-text">Security is hard to get right. Sometimes it is difficult to trust the process of creation of wallet to an online web application.</p>
|
||||||
|
<p class="card-text">Luckily you can create your own wallet using instructions here. Follow the link to find out how.</p>
|
||||||
|
<p><a href="/wallet/how-to">Create Your Own</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/feather.min.js" integrity="sha384-uO3SXW5IuS1ZpFPKugNNWqTZRRglnUJK6UAZ/gxOX80nxEkN9NcGZTftn6RzhGWE" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js" integrity="sha384-zNy6FEbO50N+Cg5wap8IKA4M/ZnLJgzc6w2NqACZaK0u0FXfOWRRJOnQtpZun8ha" crossorigin="anonymous"></script><script src="/javascripts/dashboard.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Reference in New Issue
Block a user