functional
This commit is contained in:
parent
1ffe5d8f0f
commit
b161f0892e
1
.gitignore
vendored
1
.gitignore
vendored
@ -116,3 +116,4 @@ dist
|
|||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
config.js
|
19
config template.js
Normal file
19
config template.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
//Edit the values in this file and rename it to config.js or everyone will (rightfully) laugh at you when you ask for help.
|
||||||
|
|
||||||
|
config = {
|
||||||
|
avalonNode: "https://avalon.tld/",
|
||||||
|
database: "keyStore",
|
||||||
|
jwtSecret: "jwtSecretjwtSecretjwtSecretjwtSecret" || process.env.jwtSecret,
|
||||||
|
secret: "secretsecretsecretsecret" || process.env.jwtSecret,
|
||||||
|
mongoUrl: "mongodb://mongodbserver/",
|
||||||
|
expressPort: 3000,
|
||||||
|
fee: 0,
|
||||||
|
discordUser: "userName#1970",
|
||||||
|
accountCreator: {
|
||||||
|
username: "accountCreatorUsername",
|
||||||
|
privKey: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = config
|
70
index.js
Normal file
70
index.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
config = require("./config.js")
|
||||||
|
register = require("./register.js")
|
||||||
|
login = require("./login.js")
|
||||||
|
txHandler = require("./txHandler.js")
|
||||||
|
require("./peroidicActions/checkPayment.js")
|
||||||
|
require("./peroidicActions/pruneUnpaidAccounts.js")
|
||||||
|
|
||||||
|
express = require('express')
|
||||||
|
jwt = require('jsonwebtoken')
|
||||||
|
bodyParser = require('body-parser')
|
||||||
|
javalon = require("javalon")
|
||||||
|
|
||||||
|
javalon.init({api: config.avalonNode.slice(0, -1)})
|
||||||
|
|
||||||
|
app = express()
|
||||||
|
app.use(bodyParser.json(),function (req, res, next) {
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*')
|
||||||
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST')
|
||||||
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
|
||||||
|
|
||||||
|
res.setHeader('Content-Type', 'application/json')
|
||||||
|
res.setHeader('Access-Control-Allow-Credentials', true)
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
const authenticateJWT = (req, res, next) => {
|
||||||
|
const authHeader = req.headers.authorization;
|
||||||
|
|
||||||
|
if (authHeader) {
|
||||||
|
const token = authHeader.split(' ')[1];
|
||||||
|
jwt.verify(token, config.jwtSecret, (err, user) => {
|
||||||
|
if (err) {
|
||||||
|
console.log(err)
|
||||||
|
return res.send({"Error": "Auth Failure"})
|
||||||
|
}
|
||||||
|
|
||||||
|
req.user = user
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.redirect(401, "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app.post('/register', function (req, res) {
|
||||||
|
register(req.body.username, req.body.password).then(x => {
|
||||||
|
res.send({"Message": x})
|
||||||
|
}).catch( e => {
|
||||||
|
res.send({"Error": e})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.post('/login', function (req, res) {
|
||||||
|
login(req.body.username, req.body.password).then(x => {
|
||||||
|
res.send({"accessToken":x})
|
||||||
|
}).catch( e => {
|
||||||
|
res.send({"Message": e})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.post('/submit',authenticateJWT, function (req, res) {
|
||||||
|
txHandler(req.body.tx, req.user).then(x => {
|
||||||
|
res.send({"Message": x})
|
||||||
|
}).catch( e => {
|
||||||
|
res.send({"Message": e})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log("Up on: "+config.expressPort)
|
||||||
|
app.listen(config.expressPort)
|
29
login.js
Normal file
29
login.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
mongo = require("./mongoHelp")
|
||||||
|
config = require("./config.js")
|
||||||
|
crypto = require('crypto')
|
||||||
|
jwt = require('jsonwebtoken')
|
||||||
|
|
||||||
|
accessTokenSecret = config.secret;
|
||||||
|
|
||||||
|
function login(username, password) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
mongo.get(config.database, "users", {"username":username}).then(userArr => {
|
||||||
|
hashedStr = crypto.createHmac('sha256', config.secret).update(password).digest('hex')
|
||||||
|
if (userArr.length != 1){
|
||||||
|
//No user is registered to that address
|
||||||
|
reject("Error")
|
||||||
|
} else if (hashedStr != userArr[0].password){
|
||||||
|
// Password Doesn't Match
|
||||||
|
reject("Error")
|
||||||
|
} else {
|
||||||
|
const accessToken = jwt.sign({
|
||||||
|
username: userArr[0].username,
|
||||||
|
}, config.jwtSecret, { expiresIn: '7d' })
|
||||||
|
resolve(accessToken)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = login
|
58
mongoHelp.js
Normal file
58
mongoHelp.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
var MongoClient = require('mongodb').MongoClient
|
||||||
|
config = require("./config")
|
||||||
|
|
||||||
|
var url = config.mongoUrl
|
||||||
|
var options= {
|
||||||
|
useNewUrlParser: true,
|
||||||
|
useUnifiedTopology: true,
|
||||||
|
promiseLibrary: global.Promise}
|
||||||
|
|
||||||
|
function put(db,collection, object){
|
||||||
|
const client = new MongoClient(url, options)
|
||||||
|
client.connect()
|
||||||
|
client.db(db).collection(collection).insertOne(object).then((value) =>{client.close();return value})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.put = put
|
||||||
|
|
||||||
|
function get(db, collection, object){
|
||||||
|
const client = new MongoClient(url, options)
|
||||||
|
client.connect()
|
||||||
|
return client.db(db).collection(collection).find(object).toArray().then((value) =>{client.close();return value})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.get = get
|
||||||
|
|
||||||
|
function getUnique(db, collection, field,object){
|
||||||
|
const client = new MongoClient(url, options)
|
||||||
|
client.connect()
|
||||||
|
return client.db(db).collection(collection).distinct(field,object).then((value) =>{client.close();return value})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exports.getUnique = getUnique
|
||||||
|
|
||||||
|
function aggregate(db,collection,agg){
|
||||||
|
const client = new MongoClient(url, options)
|
||||||
|
client.connect()
|
||||||
|
return client.db(db).collection(collection).aggregate(agg).toArray().then((value) =>{client.close();return value})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.aggregate = aggregate
|
||||||
|
|
||||||
|
function deleteOne(db, collection, object) {
|
||||||
|
const client = new MongoClient(url, options)
|
||||||
|
client.connect()
|
||||||
|
client.db(db).collection(collection).deleteOne(object).then((value) =>{client.close();return value})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.deleteOne = deleteOne
|
||||||
|
|
||||||
|
function update(db, collection, search,update) {
|
||||||
|
const client = new MongoClient(url, options)
|
||||||
|
client.connect()
|
||||||
|
client.db(db).collection(collection).updateOne(search,{$set:update}).then((value) =>{client.close();return value})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.update = update
|
||||||
|
|
51
peroidicActions/checkPayment.js
Normal file
51
peroidicActions/checkPayment.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
mongo = require("../mongoHelp.js")
|
||||||
|
config = require("../config.js")
|
||||||
|
|
||||||
|
javalon = require("javalon")
|
||||||
|
|
||||||
|
function checkPayment(){
|
||||||
|
javalon.getAccountHistory(config.accountCreator.username, 0, (err, blocks) => {
|
||||||
|
if (err) {
|
||||||
|
console.log(err)
|
||||||
|
} else {
|
||||||
|
blocks.forEach(element => {
|
||||||
|
if (element.txs[0].type == 3) {
|
||||||
|
if (element.txs[0].data.memo.length > 8){
|
||||||
|
mongo.get(config.database, "users", {_id: element.txs[0].data.memo}).then(userArr => {
|
||||||
|
if (userArr.length != 1){
|
||||||
|
console.log("UserArray too long, this could indicate duplicate IDs which would be bad")
|
||||||
|
} else {
|
||||||
|
console.log(element.txs[0].data.amount , userArr[0].price)
|
||||||
|
if (element.txs[0].data.memo == userArr[0]._id && element.txs[0].data.amount >= userArr[0].price && userArr[0].status == "Inactive" ){
|
||||||
|
id = userArr[0]._id
|
||||||
|
|
||||||
|
tx = {
|
||||||
|
type: 0,
|
||||||
|
data: {
|
||||||
|
pub: userArr[0].keys.pub,
|
||||||
|
name: userArr[0].username
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signedTx = javalon.sign(config.accountCreator.privKey,config.accountCreator.username, tx)
|
||||||
|
javalon.sendTransaction(signedTx, function(err, res) {
|
||||||
|
if (err){
|
||||||
|
console.log(err)
|
||||||
|
} else {
|
||||||
|
userArr[0].status = "Active"
|
||||||
|
mongo.update(config.database, "users", {_id: id}, userArr[0])
|
||||||
|
console.log(res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setInterval(checkPayment, 60000)
|
||||||
|
|
23
peroidicActions/pruneUnpaidAccounts.js
Normal file
23
peroidicActions/pruneUnpaidAccounts.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
mongo = require("../mongoHelp.js")
|
||||||
|
config = require("../config.js")
|
||||||
|
|
||||||
|
javalon = require("javalon")
|
||||||
|
|
||||||
|
function pruneUnpaidAccounts(){
|
||||||
|
agg = [ {'$match': {
|
||||||
|
timeLimit: { $lt: Date.now()}
|
||||||
|
}},
|
||||||
|
{'$match': {
|
||||||
|
status: "Inactive"
|
||||||
|
}}]
|
||||||
|
mongo.aggregate(config.database, "users", agg).then(oldArr => {
|
||||||
|
oldArr.forEach(element => {
|
||||||
|
mongo.deleteOne(config.database, "users", {_id:element._id})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setInterval(pruneUnpaidAccounts, 3600000)
|
47
register.js
Normal file
47
register.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
mongo = require("./mongoHelp.js")
|
||||||
|
config = require("./config.js")
|
||||||
|
accountPrice = require("./utils/accountPrice.js")
|
||||||
|
|
||||||
|
crypto = require("crypto")
|
||||||
|
uuidv4 = require('uuid/v4')
|
||||||
|
javalon = require("javalon")
|
||||||
|
|
||||||
|
|
||||||
|
function register(username, password){
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
userObj = {
|
||||||
|
_id: uuidv4(),
|
||||||
|
username: username,
|
||||||
|
status: "Inactive",
|
||||||
|
timeLimit: Date.now()+604800000
|
||||||
|
}
|
||||||
|
|
||||||
|
mongo.get(config.database, "users", {"username":username}).then(resArr => {
|
||||||
|
if (resArr.length != 0 ){
|
||||||
|
reject("Username is awaiting creation and will be available at "+new Date(resArr[0].timeLimit)+" if it remains unpaid")
|
||||||
|
} else {
|
||||||
|
javalon.getAccount(username, (err, account) => {
|
||||||
|
if (!err) {
|
||||||
|
reject("Username already exists")
|
||||||
|
} else {
|
||||||
|
userObj.keys = javalon.keypair()
|
||||||
|
userObj.password = crypto.createHmac('sha256', config.secret).update(password).digest('hex')
|
||||||
|
accountPrice(username).then(price => {
|
||||||
|
console.log(price)
|
||||||
|
console.log(parseFloat(price)+config.fee)
|
||||||
|
userObj.price = parseFloat(price)+config.fee
|
||||||
|
hPrice = (userObj.price/100)
|
||||||
|
mongo.put(config.database, "users",userObj)
|
||||||
|
resolve("Account setup: account will be accessible after sending "+hPrice+" DTC to "+config.accountCreator.username+" with a memo line of '"+ userObj._id+"' or contact "+config.discordUser+" on Discord to arrange alternate payment")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = register
|
31
txHandler.js
Normal file
31
txHandler.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
mongo = require("./mongoHelp.js")
|
||||||
|
config = require("./config.js")
|
||||||
|
javalon = require("javalon")
|
||||||
|
|
||||||
|
|
||||||
|
function txHandler(tx,user){
|
||||||
|
return new Promise((resolve,reject) => {
|
||||||
|
mongo.get(config.database, "users", {"username": user.username}).then(userArr => {
|
||||||
|
if (userArr[0].status == "Inactive"){
|
||||||
|
reject(userArr[0].username+" has not been activated send "+parseFloat(userArr[0].price)/100+" DTC to "+config.accountCreator.username+" with a memo line of '"+ userArr[0]._id+"' or contact "+config.discordUser+" on Discord to arrange alternate payment")
|
||||||
|
}
|
||||||
|
else if (userArr.length == 0){
|
||||||
|
reject("Something serious has gone wrong contact "+config.discordUser+" on Discord")
|
||||||
|
} else {
|
||||||
|
console.log(userArr[0])
|
||||||
|
signedTx = javalon.sign(userArr[0].keys.priv, userArr[0].username, tx)
|
||||||
|
javalon.sendTransaction(signedTx, function(err, res) {
|
||||||
|
if (err){
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
resolve(res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = txHandler
|
21
utils/accountPrice.js
Normal file
21
utils/accountPrice.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
fetch = require("node-fetch")
|
||||||
|
|
||||||
|
config = require("../config.js")
|
||||||
|
|
||||||
|
function accountPrice(username){
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fetch(config.avalonNode+"accountPrice/"+username, {
|
||||||
|
method: 'get',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json, text/plain, */*',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
resolve(res.text())
|
||||||
|
}).catch(function(error) {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = accountPrice
|
Loading…
Reference in New Issue
Block a user