Created
January 2, 2023 23:46
-
-
Save HarcourtHamsa/25b39ab05d0331ac7e5b4176085bddef to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import express = require("express"); | |
import multer = require("multer"); | |
const router = express.Router(); | |
const MongoClient = require("mongodb").MongoClient; | |
const mongo = require("mongodb"); | |
var mongoose = require("mongoose"); | |
const assert = require("assert"); | |
const fs = require("fs"); | |
// const nodemailer = require('nodemailer') | |
const { v4: uuidv4 } = require("uuid"); | |
const callbackify = require("util").callbackify; | |
const session = require("express-session"); | |
const crypto = require("crypto"); | |
const Config = require("../srv_config").Config; | |
var _ = require("lodash"); | |
var async = require("async"); | |
export default router; | |
// import { User } from '../srv_user' | |
import { | |
CryptoType, | |
NewPaymentCardPost, | |
NewPaymentCryptoPost, | |
NewPaymentPostResponse, | |
OperationResult, | |
OperationResultResponse, | |
OperationUserAvatarUpload, | |
SetPaymentDefault, | |
SharedAvatarCheck, | |
SharedRegex, | |
SharedReportCheck as SharedReportCheck, | |
SignUpResponse, | |
UserReportPost, | |
} from "../srv_shared"; | |
import { EtherumConfig } from "../srv_config"; | |
import { | |
Token, | |
AuthUserResponse, | |
AuthUserCode, | |
AccountStatus, | |
VerificationResult, | |
SignUpCode, | |
TokenState, | |
} from "../srv_shared"; | |
import { encrypt, decrypt, EncData } from "../srv_encdata"; | |
import { | |
displayNameBelongstoSession, | |
getRandomArbitrary, | |
getSessionToken, | |
L, | |
redirectToLogin, | |
render, | |
render401, | |
render404, | |
sendMail, | |
} from "../srv_util"; | |
import { getMongoDBCollection } from "../srv_db"; | |
import { | |
deleteLocalImageFilesFromRequest, | |
ImageIntent, | |
MongoAlbum, | |
MongoImage, | |
MongoImageData, | |
} from "./r_album"; | |
import { MongoTimeoutError, ObjectId } from "mongodb"; | |
import { send } from "process"; | |
// import { ObjectId } from 'mongoose'; | |
// import { mongo } from 'mongoose'; | |
export enum UserRole { | |
user, | |
// admin, | |
} | |
export type MongoUser = { | |
_id?: object; | |
displayname: string; | |
dob: Date; | |
email: string; | |
password: EncData; | |
status: AccountStatus; | |
creationDate: Date; | |
verificationKey: string; | |
description: string; | |
userIcon: string; | |
role: UserRole; | |
}; | |
type Author = { | |
name: string; | |
imgUri: string; | |
}; | |
type Album = { | |
id: string; | |
name: string; | |
remaining: number; | |
price: string; | |
description: string; | |
author: Author; | |
coverImageUri: string; | |
} | |
function isUndefined(mu: MongoUser): boolean { | |
return ( | |
mu.displayname === undefined || | |
mu.dob === undefined || | |
mu.email === undefined || | |
mu.password === undefined || | |
mu.status === undefined || | |
mu.creationDate === undefined || | |
mu.verificationKey === undefined | |
); | |
} | |
class SignUpForm { | |
constructor( | |
public displayname: string, | |
public dob: string, | |
public email: string, | |
public raw_password: string | |
) {} | |
} | |
class SignUpCheckResult { | |
constructor( | |
public isValid: boolean, | |
public err: string, | |
public code: SignUpCode | |
) {} | |
} | |
// Verify signup form | |
function verifySignInForm(sf: SignUpForm): SignUpCode { | |
if (sf.displayname.length < 5) { | |
return SignUpCode.DISPLAY_NAME_TOO_SHORT; | |
} | |
if (SharedRegex.displayname.test(String(sf.displayname)) == false) { | |
return SignUpCode.DISPLAY_NAME_NON_VALID_CHARACTERS | |
} | |
const email_regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; | |
if (email_regex.test(String(sf.email).toLowerCase()) === false) { | |
return SignUpCode.EMAIL_FORMAT_INCORRECT | |
} | |
const dob = new Date(sf.dob); | |
const today = new Date(); | |
var age = today.getFullYear() - dob.getFullYear(); | |
var m = today.getMonth() - dob.getMonth(); | |
if (m < 0 || (m === 0 && today.getDate() < dob.getDate())) { | |
age--; | |
} | |
if (age < 21) { | |
return SignUpCode.NOT_OLD_ENOUGH; | |
} | |
if (sf.raw_password.length < 8) { | |
return SignUpCode.PASSWORD_TOO_SHORT; | |
} | |
if (SharedRegex.password.test(sf.raw_password) === false) { | |
return SignUpCode.PASSWORD_NO_UPPERCASE_CHARS; | |
} | |
return SignUpCode.OK; | |
} | |
// Check if user already exists | |
function handleCallbackWhenAlreadyRegistered( | |
sf: SignUpForm, | |
callback: (res: SignUpCode, vk: string) => any | |
) { | |
getUserByDisplayname(sf.displayname, (user) => { | |
if (user != null) { | |
callback(SignUpCode.USER_ALREADY_REGISTERED, null); | |
} else { | |
callback(SignUpCode.EMAIL_ALREADY_REGISTERED, null); | |
} | |
}); | |
} | |
// Upload new user to database | |
function upsertUser( | |
sf: SignUpForm, | |
callback: (res: SignUpCode, vk: string) => any | |
) { | |
getMongoDBCollection("users", (collection) => { | |
// const vk = getRandomArbitrary(1000, 1000000).toString() | |
const vk = uuidv4(); | |
const filter = { | |
$or: [{ displayname: sf.displayname }, { email: sf.email }], | |
}; | |
const password = encrypt(sf.raw_password); | |
const user: MongoUser = { | |
displayname: sf.displayname, | |
dob: new Date(sf.dob), | |
email: sf.email, | |
password: password, | |
status: AccountStatus.notVerified, | |
creationDate: new Date(), | |
verificationKey: vk, | |
description: "", | |
userIcon: "/avatar.png", | |
role: UserRole.user, | |
}; | |
assert(isUndefined(user) === false); | |
const upsert_val = { $setOnInsert: user }; | |
const options = { upsert: true }; | |
collection.updateOne(filter, upsert_val, options, (err, result) => { | |
if (err) throw err; | |
if (result.upsertedCount == 1) callback(SignUpCode.OK, vk); | |
else if (result.modifiedCount == 0) | |
handleCallbackWhenAlreadyRegistered(sf, callback); | |
else callback(SignUpCode.SERVER_ERROR, vk); | |
}); | |
}); | |
} | |
// Process new user and send verification mail | |
function processNewUser(sf: SignUpForm, res: express.Response) { | |
upsertUser(sf, (code: SignUpCode, vk: string) => { | |
L("Upsert new user result code is " + code.toString()) | |
if (code == SignUpCode.OK) { | |
L("Upsert success. Sending verification email.") | |
let fs = require('fs') | |
let path = require('path') | |
fs.readFile(path.join(__dirname, '../../template/verification-email.txt'), 'utf8', (err: Error, data: string) => { | |
if (err) throw err | |
let parsed_body = data.replace('VERIFICATION_KEY', vk) | |
parsed_body = parsed_body.replace('/DISPLAY_NAME/', '/' + sf.displayname + '/') | |
parsed_body = parsed_body.replace('DISPLAY_NAME', sf.displayname) | |
parsed_body = parsed_body.replace('EMAIL', sf.email) | |
parsed_body = parsed_body.replace('HOST_URI', Config.hostUri) | |
sendMail(sf.email, "Kunda Box Verification Email", parsed_body, (err) => { | |
if (err) { | |
L(`Failed to send verification email for ${sf.displayname} with verification code ${vk}`) | |
} | |
// Even if the verification mail fails - we'll still accept the Album | |
const srv_res = new SignUpResponse(code) | |
res.send(srv_res.toJsonStr()) | |
}) | |
}) | |
res.send(`{"code":"${SignUpCode.OK}"}`); | |
res.end(); | |
} else { | |
res.send(`{"code":"${SignUpCode.USER_ALREADY_REGISTERED}"}`); | |
res.end(); | |
} | |
}) | |
} | |
// Fetch albums owned by user | |
async function getOwnedAlbum(displayname: string) { | |
const col_transaction = await getMongoDBCollection("transactions"); | |
const col_user = await getMongoDBCollection("users"); | |
const col_album = await getMongoDBCollection("albums"); | |
const user = await col_user.findOne({ displayname: displayname }); | |
const transaction = await col_transaction | |
.find({ buyerId: user._id }) | |
.toArray(); | |
for (const content of transaction) { | |
console.log(content) | |
if(content.buyerTx.status == "Completed"){ | |
const album = await col_album.find({ _id: content.albumId }).toArray(); | |
return album; | |
} | |
} | |
} | |
// ---- Fetch albums made by user ------- // | |
async function getMadeAlbum(displayname:string) { | |
const col_album = await getMongoDBCollection("albums") | |
const albums = await col_album.find({author: displayname}).toArray() | |
return albums | |
} | |
// ---- Fetch albums being sold by user ------ // | |
async function getSellingAlbum(displayname: string) { | |
const col_transaction = await getMongoDBCollection("transactions"); | |
const col_user = await getMongoDBCollection("users"); | |
const col_album = await getMongoDBCollection("albums"); | |
const user = await col_user.findOne({ displayname: displayname }); | |
const transaction = await col_transaction | |
.find({ buyerId: user._id }) | |
.toArray(); | |
for (const content of transaction) { | |
console.log(content) | |
if(content.buyerTx.status == "Selling"){ | |
const album = await col_album.find({ _id: content.albumId }).toArray(); | |
return album; | |
} | |
} | |
} | |
export async function getUserByDisplaynameAsync( | |
displayname: string | |
): Promise<MongoUser> { | |
const col = getMongoDBCollection("users"); | |
const user: MongoUser = await col.findOne({ displayname: displayname }); | |
return user; | |
} | |
// Fetch user by display name | |
export function getUserByDisplayname(displayname: string, callback: (user: MongoUser) => any) { | |
getMongoDBCollection('users', (collection) => { | |
const find_res = collection.findOne({ displayname: displayname }, (err, user: MongoUser) => { | |
if (err) throw err; | |
// const user = (result) ? User.fromJson(result) : null | |
callback(user) | |
}) | |
}) | |
} | |
export async function getUserByTokenKeyAsync(tokenKey: string): Promise<MongoUser> { | |
const col = getMongoDBCollection('tokens') | |
const res = await col.findOne({ key: tokenKey }) | |
if (res) { | |
return await getUserByDisplaynameAsync(res.displayname) | |
} else { | |
return null | |
} | |
} | |
// Fetch user by token | |
export function getUserByTokenKey(token_key: string, callback: (user?: MongoUser) => any) { | |
getMongoDBCollection('tokens', (collection) => { | |
const find_res = collection.findOne({ key: token_key }, (err, res) => { | |
if (err) throw err | |
if (res) { | |
getUserByDisplayname(res.displayname, (user) => { | |
callback(user) | |
}) | |
} | |
else { | |
callback(null) | |
} | |
}) | |
}) | |
} | |
// Fetch user by email | |
function getUserByEmail(email: string, callback: (user?: MongoUser) => any) { | |
getMongoDBCollection('users', (collection) => { | |
collection.findOne({ email: email }, (err, user: MongoUser) => { | |
if (err) throw err; | |
// const user = (res) ? User.fromJson(res) : null | |
callback(user) | |
}) | |
}) | |
} | |
// Fetch user by ID | |
export function getUserById(id: object, callback: (user?: MongoUser) => any) { | |
getMongoDBCollection('users', (collection) => { | |
collection.findOne({ _id: id }, (err, user: MongoUser) => { | |
if (err) throw err; | |
callback(user) | |
}) | |
}) | |
} | |
// Set account status -> active, inactive, suspended | |
function setAccountStatus(displayname: string, newStatus: AccountStatus) { | |
// const client = new MongoClient(Config.mongoDBUri) | |
getMongoDBCollection('users', (collection) => { | |
const find_res = collection.updateOne( | |
{ displayname: displayname }, | |
{ | |
$set: { | |
status: newStatus.toString(), | |
} | |
} | |
) | |
}) | |
} | |
// Process new user's activation | |
function processUserVerification(displayname: string, vk: string, res: express.Response) { | |
getUserByDisplayname(displayname, (user) => { | |
if (user) { | |
if (user.status != AccountStatus.suspended) { | |
if (user.verificationKey == vk) { | |
setAccountStatus(displayname, AccountStatus.active) | |
res.render('v_verify', { verifyState: VerificationResult.OK }) | |
return | |
} | |
} | |
} | |
res.render('v_verify', { verifyState: VerificationResult.FAILED }) | |
}) | |
} | |
function saveToken(token: Token) { | |
getMongoDBCollection('tokens', (collection) => { | |
collection.insert(token.toJson()) | |
}) | |
} | |
function isAuthNull(req: any): boolean { | |
return req.session.auth === undefined || | |
req.session.authDate === undefined || | |
req.session.token === undefined | |
} | |
function resetAuthSession(req: any) { | |
req.session.auth = undefined | |
req.session.authDate = undefined | |
req.session.token = undefined | |
} | |
export function getSessionTokenKey(req: any): string { | |
if (req.session.token) | |
return Token.fromJsonStr(req.session.token).key | |
else | |
return null | |
} | |
export async function getSessionUserAsync(req: any): Promise<MongoUser> { | |
const tk = getSessionTokenKey(req) | |
const mongoUser = await getUserByTokenKeyAsync(tk) | |
return mongoUser | |
} | |
export function getSessionUser(req: any, callback: (user: MongoUser) => any) { | |
const key = getSessionTokenKey(req) | |
if (key) | |
getUserByTokenKey(key, callback) | |
else | |
callback(null) | |
} | |
function isDateWithinXMonthsAgo(date: Date, xMonths: number) { | |
var d = new Date(date); | |
var m = d.getMonth(); | |
d.setMonth(d.getMonth() - xMonths); | |
var diff = (m + 12 - d.getMonth()) % 12; | |
if (diff < xMonths) d.setDate(0) | |
return d; | |
} | |
export function isSessionAuthAlreadyValid(req: any): boolean { | |
if (req.session.auth == true) { | |
if (isDateWithinXMonthsAgo(req.session.authDate, 1)) { | |
return true | |
} | |
else { | |
return false | |
} | |
} | |
else { | |
return false | |
} | |
} | |
function expireToken(token: Token) { | |
getMongoDBCollection('tokens', (collection) => { | |
const filter = { | |
key: token.key | |
} | |
collection.updateOne( | |
{ key: token.key }, | |
{ | |
$set: { | |
state: TokenState.expired | |
} | |
} | |
) | |
}) | |
} | |
function logoutUser(token_key: string, req: any, res: express.Response) { | |
L('Attempting to log out with tk - ' + token_key) | |
const sendBack = (resStr: string) => { | |
res.send(JSON.stringify({ | |
result: resStr | |
})) | |
} | |
if (isAuthNull(req)) { | |
L('No run-time token found. Nothing to do, so logging out') | |
res.send(JSON.stringify({ result: 'ok' })) | |
} | |
else { | |
getUserByTokenKey(token_key, (user?: MongoUser) => { | |
if (user) { | |
const session_token = Token.fromJsonStr(req.session.token) | |
if (!session_token) { | |
L('Token failed to be extracted') | |
resetAuthSession(req) | |
} else { | |
if (token_key === session_token.key) { | |
if (session_token.state == TokenState.valid) { | |
L("Token matches, so user logged out") | |
expireToken(session_token) | |
resetAuthSession(req) | |
sendBack("ok") | |
} | |
else { | |
L('Failed to log out - token is already not valid') | |
sendBack("failed") | |
} | |
} | |
else { | |
L('Failed to log out - token key did not match') | |
sendBack("failed") | |
} | |
} | |
} | |
else { | |
L('Failed to logout - token key did not find a user') | |
sendBack("failed") | |
} | |
}) | |
} | |
} | |
function updateUserPassword(displayname: string, raw_password: string) { | |
getMongoDBCollection('users', (collection) => { | |
const password = encrypt(raw_password) | |
collection.updateOne({ displayname: displayname }, { | |
$set: { | |
password: password//.toJson() | |
} | |
}) | |
}) | |
} | |
function processPasswordReset(displayname: string, rk: string, raw_password: string, res: express.Response) { | |
L(`Processing password reset - displayname: ${displayname} rk: ${rk} raw password: ${raw_password}`) | |
getMongoDBCollection('resetkeys', (collection) => { | |
collection.findOne({ key: rk }, (err, document) => { | |
if (err) throw err | |
if (document) { | |
if (document.displayname == displayname) { | |
const key_date = new Date(document.date) | |
const delta_hours = Math.abs(new Date().getTime() - key_date.getTime()) / (1000 * 60 * 60) | |
L(`Delta hours is ${delta_hours}`) | |
if (delta_hours <= 0.5) { | |
L('Reset Key matches and is within time') | |
updateUserPassword(displayname, raw_password) | |
res.send(JSON.stringify({ result: "ok" })) | |
} | |
else { | |
L('Reset key matches but is NOT within time') | |
res.send(JSON.stringify({ result: "failed" })) | |
} | |
} | |
else { | |
L('Name did not match provided verification key') | |
res.send(JSON.stringify({ result: "failed" })) | |
} | |
} | |
else { | |
L('No entry for provided reset key') | |
res.send(JSON.stringify({ result: "failed" })) | |
} | |
}) | |
}) | |
} | |
function addResetKeyEntry(user: MongoUser, key: string, callback: () => any) { | |
getMongoDBCollection('resetkeys', (collection) => { | |
collection.insertOne({ | |
displayname: user.displayname, | |
key: key, | |
date: new Date().toString() | |
}, (err, res) => { | |
if (err) throw err | |
callback() | |
}) | |
}) | |
} | |
function processPasswordResetEmail(email: string, req: any, res: express.Response) { | |
const sendBack = (result: OperationResult, errDesc?: string) => { | |
const op: OperationResultResponse = { result: result, errDesc: errDesc } | |
res.send(op) | |
} | |
getUserByEmail(email, (user) => { | |
if (user) { | |
L('User found ' + email) | |
if (user.status != AccountStatus.suspended) { | |
L('User is eligible for password reset email') | |
let fs = require('fs') | |
let path = require('path') | |
fs.readFile(path.join(__dirname, '../../template/resetPassword-email.txt'), 'utf8', (err: Error, data: string) => { | |
if (err) throw err | |
// const key = getRandomArbitrary(1000, 1000000).toString() | |
const key = uuidv4() | |
addResetKeyEntry(user, key, () => { | |
let parsed_body = data.replace('RESET_KEY', key) | |
parsed_body = parsed_body.replace('/DISPLAY_NAME/', '/' + user.displayname + '/') | |
parsed_body = parsed_body.replace('DISPLAY_NAME', user.displayname) | |
parsed_body = parsed_body.replace('HOST_URI', Config.hostUri) | |
sendMail(user.email, 'Kunda Box Password Reset', parsed_body, (err) => { | |
if (err) { | |
L(`Failed to send reset email`) | |
sendBack(OperationResult.error, 'Server Error - Failed to send reset email. Please contact an admin') | |
} else { | |
L('Success in sending reset email') | |
sendBack(OperationResult.ok) | |
} | |
}) | |
}) | |
}) | |
} | |
else { | |
L('Failed since user is suspended') | |
sendBack(OperationResult.error, 'Failed to reset email as user is suspended') | |
} | |
} | |
else { | |
L('Failed to find user by email') | |
sendBack(OperationResult.error, 'Failed to find user in Database. Please contact an admin') | |
} | |
}) | |
} | |
function randomizeTokenKey(token: Token) { | |
token.key = crypto.randomBytes(20).toString('hex'); | |
} | |
function loginUser(email: string, raw_password: string, req: any, res: express.Response) { | |
if (isSessionAuthAlreadyValid(req) == true) { | |
L('Session is already active') | |
const res_code = AuthUserCode.success | |
const session_token = Token.fromJsonStr(req.session.token) | |
const auth_res = new AuthUserResponse(res_code, session_token.key) | |
res.send(auth_res.toJsonStr()) | |
} | |
else { | |
const failFunc = (errDes: string) => { | |
L(errDes) | |
const auth_res = new AuthUserResponse(AuthUserCode.failed) | |
res.send(auth_res.toJsonStr()) | |
resetAuthSession(req) | |
} | |
getUserByEmail(email, (user) => { | |
let res_code = AuthUserCode.failed | |
let res_token_key: string = null | |
if (user) { | |
L('User found - ' + user.email) | |
if (user.status == AccountStatus.active) { | |
const raw_user_password = decrypt(user.password) | |
if (raw_user_password == raw_password) { | |
L('Auth successful') | |
const token = new Token() | |
token.displayname = user.displayname | |
randomizeTokenKey(token) | |
token.date = new Date() | |
assert(token.isValid()) | |
saveToken(token) | |
req.session.auth = true | |
req.session.authDate = new Date() | |
req.session.token = token.toJsonStr() | |
res_code = AuthUserCode.success | |
res_token_key = token.key | |
const auth_res = new AuthUserResponse(res_code, res_token_key) | |
res.send(auth_res.toJsonStr()) | |
} | |
else { | |
failFunc('Auth failed due to password is incorrect') | |
} | |
} | |
else { | |
failFunc('Auth failed due to status') | |
} | |
} | |
else { | |
failFunc('Auth failed due to no user found') | |
} | |
}) | |
} | |
} | |
router.post('/', (req: express.Request, res: express.Response) => { | |
L("Post user from " + req.ip); | |
var sf = new SignUpForm( | |
req.body["displayname"], | |
req.body["dob"], | |
req.body["email"], | |
req.body["password"] | |
) | |
if (!sf.displayname || !sf.dob || !sf.email || !sf.raw_password) { | |
L("New form verification failed") | |
const srv_res = new SignUpResponse(SignUpCode.SERVER_ERROR) | |
res.send(srv_res.toJsonStr()) | |
} else { | |
const form_res = verifySignInForm(sf) | |
if (form_res != SignUpCode.OK) { | |
L("New form verification failed") | |
const srv_res = new SignUpResponse(form_res) | |
res.send(srv_res.toJsonStr()) | |
} | |
else { | |
L("New form verification passed") | |
processNewUser(sf, res) | |
} | |
} | |
}); | |
router.get('/:user/verify', (req: any, res: express.Response) => { | |
L('Verification request from' + req.ip) | |
const display_name = req.params.user.toString() | |
const vk = req.query.vk.toString() | |
if (!display_name || !vk) | |
res.status(400) | |
else { | |
L('Verifying user ' + display_name) | |
processUserVerification(display_name, vk, res) | |
} | |
}) | |
router.post('/login', (req: express.Request, res: express.Response) => { | |
L('User login request from ' + req.ip) | |
let email = req.body['email'] | |
const raw_password = req.body['password'] | |
if (!email || !raw_password) { | |
L('Invalid user post params request') | |
const auth_res = new AuthUserResponse(AuthUserCode.failed) | |
res.send(auth_res.toJsonStr()) | |
} else { | |
email = email.toString().toLowerCase() | |
L('Logging in user ' + email) | |
loginUser(email, raw_password, req, res) | |
} | |
}) | |
router.post('/logout', (req: express.Request, res: express.Response) => { | |
L('User logout request from ' + req.ip) | |
const token_key = req.body['token_key'] | |
if (!token_key) | |
throw new Error("Invalid req.body") | |
logoutUser(token_key, req, res) | |
}) | |
router.get('/lostPassword', (req: any, res: express.Response) => { | |
L('/user/lostPassword request') | |
render(req, res, 'v_lostPassword', 'Lost Password') | |
}) | |
router.post('/requestPasswordResetEmail', (req: express.Request, res: express.Response) => { | |
L('User password reset request from ' + req.ip) | |
const email = req.body['email'] | |
if (!email) { | |
L('Invalid email param sent') | |
const op: OperationResultResponse = { | |
result: OperationResult.error, | |
errDesc: `invalid email parameter` | |
} | |
res.send(op) | |
} | |
else | |
processPasswordResetEmail(email, req, res) | |
}) | |
router.get('/:user/changePassword', (req: any, res: express.Response) => { | |
L('/ user/changePassword ' + req.ip) | |
const displayname = req.params.user.toString() | |
const rk = req.query.rk.toString() | |
if (displayname == null || rk == null) { | |
render404(req, res, "The page you're searching for cannot be found") | |
} else { | |
res.render('v_changePassword', { | |
displayname: displayname, | |
rk: rk | |
}) | |
} | |
}) | |
router.post('/:user/changePassword', (req: any, res: express.Response) => { | |
L('User password reset post from ' + req.ip) | |
const displayname = req.params.user.toString() | |
const raw_password = req.body['password'] | |
const rk = req.body['rk'] | |
if (!raw_password || !rk || !displayname) | |
render404(req, res, "The page you're searching for cannot be found" | |
) | |
else | |
processPasswordReset(displayname, rk, raw_password, res) | |
}) | |
export function getActiveUserPayments(id: object, callback: (cryptoPayments: MongoCryptoPayment[]) => any) { | |
getMongoDBCollection('payments', cryptoCol => { | |
cryptoCol.find({ userId: id, status: PaymentStatus.active }).toArray((err, cryptoPayments: MongoCryptoPayment[]) => { | |
if (err) throw err | |
callback(cryptoPayments) | |
}) | |
}) | |
} | |
function mongoAlbum2PageAlbum(mongoAlbum: MongoAlbum, callback: (pageAlbum: Album) => any) { | |
const coverImageUri = mongoAlbum.coverImgId | |
const defaultAuthorImgUri = '/avatar.png' | |
let trimmedDescription = mongoAlbum.description | |
if (trimmedDescription.length >= 6 * 20) { | |
trimmedDescription = trimmedDescription.substring(0, 6 * 20 - 3) + '...' | |
} | |
let trimmedName = mongoAlbum.name | |
if (trimmedName.length >= 18) { | |
trimmedName = trimmedName.substring(0, 15) + '...' | |
} | |
getUserByDisplayname(mongoAlbum.author, (user?) => { | |
const imgUri = (user) ? user.userIcon : defaultAuthorImgUri | |
const pageAlbum: Album = { | |
id: mongoAlbum._id.toString(), | |
name: trimmedName, | |
remaining: mongoAlbum.quantity, | |
price: mongoAlbum.price, | |
author: { | |
name: mongoAlbum.author, | |
imgUri: imgUri | |
}, | |
coverImageUri: coverImageUri, | |
description: trimmedDescription | |
} | |
callback(pageAlbum) | |
}) | |
} | |
// function getUserCreatedAlbum(displayName: string, callback: (createdAlbums: Album[]) => any){ | |
// getMongoDBCollection('albums', (albumCollection) => { | |
// albumCollection.find({author: displayName}).toArray((err, mongoAlbums: MongoAlbum[]) => { | |
// if(err){ | |
// L('Error querying album') | |
// }else{ | |
// let createdAlbums: Album[] = [] | |
// async.forEachOf(mongoAlbums, (mongoAlbum: MongoAlbum, key, nextCallback) => { | |
// mongoAlbum2PageAlbum(mongoAlbum, (createdAlbum) => { | |
// createdAlbums.push(createdAlbum) | |
// nextCallback() | |
// }) | |
// }, (err) => { | |
// if (err) throw err | |
// callback(createdAlbums) | |
// }) | |
// // const createdPkg = { | |
// // created_album: createdAlbums | |
// // } | |
// // render(req, res, 'v_user', null, null, createdPkg) | |
// } | |
// }) | |
// }) | |
// } | |
router.get("/:user", async (req: any, res: express.Response) => { | |
L("get /user request from - " + req.ip); | |
const displayName = req.params.user.toString(); | |
if (!displayName) { | |
L("Invalid display name param"); | |
res.redirect("/"); | |
} else { | |
const selfUserDisplay = displayNameBelongstoSession(req, displayName); | |
await getUserByDisplayname(displayName, (mongoUser?: MongoUser) => { | |
if (!mongoUser) { | |
L(`Failed to get ${displayName} user from DB`); | |
res.redirect("/"); | |
} else { | |
getMongoDBCollection("albums", (albumCollection) => { | |
albumCollection | |
.find({ author: displayName }) | |
.toArray((err, mongoAlbums: MongoAlbum[]) => { | |
if (err) { | |
L("Error querying album"); | |
} else { | |
let createdAlbums: Album[] = []; | |
async.forEachOf( | |
mongoAlbums, | |
(mongoAlbum: MongoAlbum, key, nextCallback) => { | |
mongoAlbum2PageAlbum(mongoAlbum, (createdAlbum) => { | |
createdAlbums.push(createdAlbum); | |
nextCallback(); | |
}); | |
}, | |
(err) => { | |
if (err) throw err; | |
getActiveUserPayments( | |
mongoUser._id, | |
(cryptoPayments: MongoCryptoPayment[]) => { | |
const paymentsPage = | |
mongoPayments2paymentsPage(cryptoPayments); | |
// const getOwnedAlbums = async (collection: string) => { | |
// getMongoDBCollection(collection, (transactionsCol) => { | |
// transactionsCol.find({buyerId: mongoUser._id}).toArray((err, transaction) => { | |
// transaction.forEach(tran => { | |
// albumCollection.find({_id: tran.albumId}).toArray((err, albums: MongoAlbum) => { | |
// return albums | |
// }) | |
// }) | |
// }) | |
// }) | |
// } | |
// const albums = getOwnedAlbums('transactions') | |
console.log(mongoUser.displayname); | |
async function assignResult() { | |
const ownedAlbum = await getOwnedAlbum(mongoUser.displayname) | |
const madeAlbum = await getMadeAlbum(mongoUser.displayname) | |
const sellingAlbum = await getSellingAlbum(mongoUser.displayname) | |
console.log(ownedAlbum) | |
const pkg = { | |
displayName: displayName, | |
description: mongoUser.description, | |
userIconUri: mongoUser.userIcon, | |
selfUserDisplay: selfUserDisplay, | |
payments: paymentsPage, | |
status: mongoUser.status, | |
popup: { | |
header: "Delete Payment", | |
description: "Do you want to delete this payment?", | |
}, | |
ownedAlbums: ownedAlbum, | |
madeAlbums: madeAlbum, | |
sellingAlbums: sellingAlbum, | |
created_albums: createdAlbums, | |
}; | |
render(req, res, "v_user", "User", displayName, pkg); | |
} | |
assignResult() | |
// getMongoDBCollection('transactions', (transactionsCol) => { | |
// transactionsCol.find({buyerId: mongoUser._id}).toArray((err, transaction) => { | |
// // if(!transaction && transaction.buyerTx.staus !== "Completed"){ | |
// // L(`No album transaction for ${displayName} user`) | |
// // }else{ | |
// // console.log(transaction) | |
// transaction.forEach(tran => { | |
// albumCollection.find({_id: tran.albumId}).toArray((err, albums) => { | |
// // console.log(albums) | |
// // async.forEachOf(albums, (album: MongoAlbum, key, nextCallback) => { | |
// // id: album._id, | |
// // name: album.name, | |
// // price: album.price, | |
// // }) | |
// const pkg = { | |
// displayName: displayName, | |
// description: mongoUser.description, | |
// userIconUri: mongoUser.userIcon, | |
// selfUserDisplay: selfUserDisplay, | |
// payments: paymentsPage, | |
// status: mongoUser.status, | |
// popup: { | |
// header: 'Delete Payment', | |
// description: 'Do you want to delete this payment?', | |
// }, | |
// ownedAlbums: albums, | |
// created_albums: createdAlbums | |
// } | |
// render(req, res, 'v_user', 'User', displayName, pkg) | |
// }) | |
// }) | |
// // } | |
// }) | |
// }) | |
// const col_user = await getMongoDBCollection('users') | |
// const user = await col_user.findOne({displayname: displayname}) | |
// console.log(user) | |
// console.log(albums) | |
// const pkg = { | |
// displayName: displayName, | |
// description: mongoUser.description, | |
// userIconUri: mongoUser.userIcon, | |
// selfUserDisplay: selfUserDisplay, | |
// payments: paymentsPage, | |
// status: mongoUser.status, | |
// popup: { | |
// header: "Delete Payment", | |
// description: "Do you want to delete this payment?", | |
// }, | |
// ownedAlbums: ownedAlbum, | |
// created_albums: createdAlbums, | |
// }; | |
// render(req, res, "v_user", "User", displayName, pkg); | |
} | |
); | |
// const createdPkg = { | |
// created_album: createdAlbums | |
// } | |
// render(req, res, 'v_user', null, null, createdPkg) | |
}) | |
} | |
}) | |
}) | |
// let created_albums: [] | |
// getUserCreatedAlbum(displayName, ) | |
// getActiveUserPayments(mongoUser._id, (cryptoPayments: MongoCryptoPayment[]) => { | |
// const paymentsPage = mongoPayments2paymentsPage(cryptoPayments) | |
// const pkg = { | |
// displayName: displayName, | |
// description: mongoUser.description, | |
// userIconUri: mongoUser.userIcon, | |
// selfUserDisplay: selfUserDisplay, | |
// payments: paymentsPage, | |
// status: mongoUser.status, | |
// popup: { | |
// header: 'Delete Payment', | |
// description: 'Do you want to delete this payment?', | |
// }, | |
// created_albums: created_albums | |
// } | |
// render(req, res, 'v_user', 'User', displayName, pkg) | |
// }) | |
} | |
}); | |
} | |
}); | |
// Fetch report page for individual user | |
router.get("/:user/report", (req: any, res: express.Response) => { | |
L(`'user/report ${req.params.user} from ${req.ip}`); | |
getSessionUser(req, (loggedUser: MongoUser) => { | |
if (!loggedUser) { | |
L("User not logged in to report another user"); | |
redirectToLogin(req, res); | |
} else { | |
const displayName = req.params.user.toString(); | |
if (!displayName) { | |
L("Invalid display name param"); | |
res.redirect("/"); | |
} else { | |
getUserByDisplayname(displayName, (reportedUser?: MongoUser) => { | |
if (!reportedUser) { | |
L(`Falied to get ${displayName} user from DB`); | |
res.redirect("/"); | |
} else { | |
const pkg = { | |
reportingUser: loggedUser.displayname, | |
reportedUser: reportedUser.displayname, | |
}; | |
render(req, res, "v_report", "Report User", `${displayName}`, pkg); | |
} | |
}); | |
} | |
} | |
}); | |
}); | |
type MongoUserReport = { | |
_id?: object; | |
reportingUser: object; | |
reportedUser: object; | |
message: string; | |
reportOption: string; | |
}; | |
// Post user report | |
router.post('/:user/report', (req: any, res: express.Response) => { | |
L("POST /user/report request") | |
const sendError = (errStr) => { | |
const r: OperationResultResponse = { | |
result: OperationResult.error, | |
errDesc: errStr | |
} | |
res.send(r) | |
} | |
getSessionUser(req, (loggedUser: MongoUser) => { | |
if (!loggedUser) { | |
L('User not logged in') | |
sendError('User not logged in') | |
} else { | |
const userReportPost: UserReportPost = req.body | |
if (userReportPost.reportedUser == loggedUser.displayname) { | |
L('User attempted to report themselves') | |
sendError('User cannot report themselves') | |
} else { | |
if (userReportPost.reportMessage.length > SharedReportCheck.maxReportMessage) { | |
sendError(`Message exceeds limit of ${SharedReportCheck.maxReportMessage} characters`) | |
} else { | |
const userReportCol = getMongoDBCollection('userreport') | |
const userCol = getMongoDBCollection('users') | |
const lambda = async () => { | |
const reportedUser: MongoUser = await userCol.findOne({ displayname: userReportPost.reportedUser }) | |
if (!reportedUser) { | |
sendError('Server Error - Reporter user is not active in DB') | |
} else { | |
const m: MongoUserReport = { | |
reportedUser: reportedUser._id, | |
reportingUser: loggedUser._id, | |
message: userReportPost.reportMessage, | |
reportOption: userReportPost.reportOption | |
} | |
await userReportCol.insertOne(m) | |
const r: OperationResultResponse = { | |
result: OperationResult.ok | |
} | |
res.send(r) | |
} | |
} | |
lambda() | |
} | |
} | |
} | |
}) | |
}) | |
router.post('/:user/description', (req: any, res: express.Response) => { | |
L("POST /user/description request from - " + req.ip) | |
const sendBack = (result: OperationResult, errDesc: string) => { | |
const or: OperationResultResponse = { | |
result: result, | |
errDesc: errDesc | |
} | |
res.send(JSON.stringify(or)) | |
} | |
if (isSessionAuthAlreadyValid(req) == false) { | |
L('User is not authenticated') | |
sendBack(OperationResult.error, "User not authenticated") | |
} else { | |
const displayName = req.params.user.toString() | |
L(`Update request is for user ${displayName}`) | |
if (!displayName) { | |
L('Invalid display name param') | |
sendBack(OperationResult.error, "Server error") | |
} else { | |
if (!displayNameBelongstoSession(req, displayName)) { | |
L('Display name does not match session') | |
sendBack(OperationResult.error, "Server error") | |
} else { | |
getUserByDisplayname(displayName, (mongoUser?: MongoUser) => { | |
if (!mongoUser) { | |
L(`Falied to get ${displayName} user from DB`) | |
sendBack(OperationResult.error, "Server error") | |
} else { | |
mongoUser.description = req.body['description'] | |
if (!mongoUser.description) { | |
L('Invalid display name param') | |
sendBack(OperationResult.error, "Server error") | |
} else { | |
const dl = mongoUser.description.length | |
if (dl > 50000 || isNaN(dl)) { | |
L("DB operation failed to update user description") | |
sendBack(OperationResult.error, "Server error") | |
} else { | |
getMongoDBCollection('users', (collection) => { | |
collection.replaceOne({ _id: mongoUser._id }, mongoUser, (err, updateRes) => { | |
if (err) throw err | |
if (updateRes.matchedCount != 1) { | |
L("DB operation failed to update user description") | |
sendBack(OperationResult.error, "Server error") | |
} else { | |
L("Description update succesful") | |
sendBack(OperationResult.ok, "Saved!") | |
} | |
}) | |
}) | |
} | |
} | |
} | |
}) | |
} | |
} | |
} | |
}); | |
function getMulter(storage) { | |
return multer({ | |
storage: storage, | |
limits: { | |
fileSize: SharedAvatarCheck.maxPicturesSizeBytes | |
}, | |
fileFilter: (req, file, cb) => { | |
if (file.originalname.match(/\.(jpg|jpeg|png|gif)\b/)) | |
return cb(undefined, true) | |
if (file.mimetype === 'image/png' || file.mimetype === 'image/jpeg' || file.mimetype === 'image/gif') | |
return cb(undefined, true) | |
cb(new Error("File must be an image!")); | |
} | |
}).array('user-view-avatar', 1) | |
} | |
function getMulterStorage() { | |
return multer.diskStorage({ | |
destination: (req, file, cb) => { | |
cb(null, './server/uploads/') | |
}, | |
filename: (req, file, cb) => { | |
const filename = uuidv4() | |
cb(null, filename) | |
} | |
}) | |
} | |
type UserAvatarPost = { | |
contentType: any, | |
image: string, | |
} | |
function extractAvatarImgFromRequest(req): UserAvatarPost[] { | |
const fileKeys = Object.keys(req.files) | |
let images: UserAvatarPost[] = [] | |
fileKeys.forEach(key => { | |
const file = req.files[key] | |
const img = fs.readFileSync(file.path) | |
const encoded_img = img.toString('base64') | |
const finalImg: UserAvatarPost = { | |
contentType: file.mimetype, | |
image: encoded_img, | |
// name: 'user avatar img', | |
// cover: false, | |
// free: true, | |
// intent: ImageIntent.avatarIcon, | |
} | |
images.push(finalImg) | |
}) | |
return images | |
} | |
function validateExtratedAvatarImage(imgs: UserAvatarPost[]): boolean { | |
if (imgs.length != 1) | |
return false | |
if (Buffer.byteLength(imgs[0].image) >= SharedAvatarCheck.maxPicturesSizeBytes) | |
return false | |
return true | |
} | |
router.post('/avatar', (req: express.Request, res: express.Response) => { | |
L("post /user/avatar request from - " + req.ip) | |
const sendError = (errStr: string) => { | |
L(`Failed to upload avatar image with error ${errStr}`) | |
const r: OperationUserAvatarUpload = { | |
result: OperationResult.error, | |
errDesc: errStr | |
} | |
res.send(r) | |
} | |
if (isSessionAuthAlreadyValid(req)) { | |
const storage = getMulterStorage() | |
const upload = getMulter(storage) | |
upload(req, res, (err) => { | |
if (err) { | |
sendError('Files must be a JPEG, GIF or PNG and cannot exceed 1MB in size!') | |
} else { | |
const imgs = extractAvatarImgFromRequest(req) | |
deleteLocalImageFilesFromRequest(req) | |
if (!validateExtratedAvatarImage(imgs)) { | |
sendError('Images cannot exceed 1MB in size!') | |
} else { | |
getSessionUser(req, user => { | |
const userAvatarPost = imgs[0] | |
const imgDataCol = getMongoDBCollection('imagesdata') | |
const imgData: MongoImageData = { | |
data: userAvatarPost.image, | |
contentType: userAvatarPost.contentType, | |
} | |
const lambda = async () => { | |
await imgDataCol.insertOne(imgData) | |
assert(imgData._id) | |
const mongoImage: MongoImage = { | |
// contentType: userAvatarPost.contentType, | |
image: imgData._id, | |
uploaderId: user._id, | |
name: 'user avatar img', | |
cover: false, | |
free: true, | |
intent: ImageIntent.avatarIcon, | |
} | |
getMongoDBCollection('images', (imgCollection) => { | |
imgCollection.insertOne(mongoImage, (err, result) => { | |
if (err) { | |
sendError('Server Error') | |
} else { | |
const id = result.insertedId | |
L(`Generated MongoDB Img was ${id}`) | |
const avatarUri = `/images/${id}` | |
getMongoDBCollection('users', (userCollection) => { | |
const displayName = getSessionToken(req).displayname | |
userCollection.updateOne({ displayname: displayName }, { $set: { userIcon: avatarUri } }, (err, udpateRes) => { | |
if (err || udpateRes.result.ok != 1) { | |
sendError('Failed to find user') | |
} else { | |
const r: OperationUserAvatarUpload = { | |
result: OperationResult.ok, | |
avatarUri: avatarUri | |
} | |
res.send(r) | |
} | |
}) | |
}) | |
} | |
}) | |
}) | |
} | |
lambda() | |
}) | |
} | |
} | |
}); | |
} else { | |
L('User not logged in') | |
const r: OperationUserAvatarUpload = { result: OperationResult.error } | |
res.send(r) | |
} | |
}); | |
export enum PaymentStatus { | |
active = "active", | |
deleted = "deleted", | |
} | |
enum PaymentType { | |
// creditcard = "creditcard", | |
cryptocurrency = "cryptocurrency" | |
} | |
export interface MongoPayment { | |
_id?: object, | |
status: PaymentStatus, | |
userId: object, | |
type: PaymentType, | |
} | |
export interface MongoCryptoPayment extends MongoPayment { | |
cryptoType: CryptoType, | |
address: EncData, | |
privatekey: EncData, | |
default: boolean, | |
} | |
function makeDefaultPayment(userId: object, paymentId: object, callback: (res: boolean) => any) { | |
getActiveUserPayments(userId, (cryptoPayments: MongoCryptoPayment[]) => { | |
let rmvIds: object[] = [] | |
cryptoPayments.forEach((cryptoPayment: MongoCryptoPayment) => { | |
if (_.isEqual(cryptoPayment._id, paymentId) == false) { | |
rmvIds.push(cryptoPayment._id) | |
} | |
}) | |
getMongoDBCollection('payments', (col) => { | |
const updateUnsetDefault = { | |
default: false | |
} | |
col.updateMany({ _id: { $in: rmvIds } }, { $set: updateUnsetDefault }, (err, res) => { | |
if (err) throw err | |
const updateSetDefault = { | |
default: true | |
} | |
if (!res.result.ok) { | |
callback(false) | |
} else { | |
col.updateOne({ _id: paymentId }, { $set: updateSetDefault }, (err, res) => { | |
if (err) throw err | |
const r = res.result.ok == 1 | |
L(`New default payment for ${userId} is ${paymentId}`) | |
callback(r) | |
}) | |
} | |
}) | |
}) | |
}) | |
} | |
router.post('/payments/default', (req: express.Request, res: express.Response) => { | |
L("post /user/payments/default request from - " + req.ip) | |
const sendBack = (result: OperationResult, errDesc?: string) => { | |
const or: OperationResultResponse = { | |
result: result, | |
errDesc: errDesc | |
} | |
res.send(or) | |
} | |
if (!isSessionAuthAlreadyValid(req)) { | |
L('User not logged in') | |
sendBack(OperationResult.error, 'User not authenticated') | |
} else { | |
const p: SetPaymentDefault = req.body | |
if (!mongoose.Types.ObjectId.isValid(p.paymentId)) { | |
L(`Invalid post params`) | |
sendBack(OperationResult.error, 'Invalid payment ID') | |
} else { | |
getSessionUser(req, (user: MongoUser) => { | |
const mongoPayId = new mongo.ObjectId(p.paymentId) | |
makeDefaultPayment(user._id, mongoPayId, (res: boolean) => { | |
L(`Changing default payment result is - ${res}`) | |
if (!res) | |
sendBack(OperationResult.error, "Server Error - Please refresh and try again") | |
else | |
sendBack(OperationResult.ok) | |
}) | |
}) | |
} | |
} | |
}) | |
router.post('/payments/crypto', (req: express.Request, res: express.Response) => { | |
L("post /user/payments/crypto request from - " + req.ip) | |
const sendOk = (redirectUri: string, newPaymentId: string) => { | |
const or: NewPaymentPostResponse = { | |
result: OperationResult.ok, | |
redirectUri: redirectUri, | |
newPaymentId: newPaymentId, | |
} | |
res.send(or) | |
} | |
const sendFail = (errDesc: string) => { | |
const or: NewPaymentPostResponse = { | |
result: OperationResult.error, | |
errDesc: errDesc, | |
redirectUri: '', | |
newPaymentId: '', | |
} | |
res.send(or) | |
} | |
if (!isSessionAuthAlreadyValid(req)) { | |
L('User not logged in') | |
sendFail('User not authenticated') | |
} else { | |
const payPost: NewPaymentCryptoPost = req.body | |
if (!validateNewPaymentCryptoPost(payPost)) { | |
L(`Payment post failed to pass valiation`) | |
sendFail('Incorrect post format') | |
} else { | |
getSessionUser(req, (mongoUser: MongoUser) => { | |
if (!mongoUser) { | |
L('Failed to find user for current active session') | |
sendFail('User not found') | |
} else { | |
getMongoDBCollection('payments', (col) => { | |
const encPK = encrypt(payPost.privateKey) | |
const encAddress = encrypt(payPost.address) | |
col.find({ userId: mongoUser._id }).toArray((err, mongoPayments: MongoCryptoPayment[]) => { | |
if (err) throw err | |
let registeredPayment: MongoCryptoPayment = null | |
let activePayments: number = 0 | |
mongoPayments.forEach((mongoPayment) => { | |
const rawAddress = decrypt(mongoPayment.address) | |
if (rawAddress == payPost.address) | |
registeredPayment = mongoPayment | |
if (mongoPayment.status == PaymentStatus.active) | |
activePayments++ | |
}) | |
let isDefault: boolean = false | |
if (activePayments == 0 || payPost.default) | |
isDefault = true | |
L(`Is payment default - ${isDefault}`) | |
if (registeredPayment) { | |
L(`Crypto ${payPost.address} is already registered to user`) | |
if (registeredPayment.status == PaymentStatus.active) | |
sendFail('Crypto wallet is already registered to this user!') | |
else { | |
L(`Crypto was deleted, activating it again with new private key`) | |
const update = { | |
status: PaymentStatus.active, | |
privatekey: encPK, | |
default: isDefault, | |
} | |
col.updateOne({ _id: registeredPayment._id }, { $set: update }, (err, result) => { | |
if (err) throw err | |
if (result.matchedCount != 1) { | |
L('Server error') | |
sendFail('DB error') | |
} else { | |
L(`Re-activated crypto: ${registeredPayment._id}`) | |
if (isDefault) | |
makeDefaultPayment(mongoUser._id, registeredPayment._id, (res: boolean) => { | |
if (!res) | |
sendFail('Server Error setting payment as default. Please refresh and try again.') | |
else | |
sendOk(`/user/${mongoUser.displayname}`, registeredPayment._id.toString()) | |
}) | |
else | |
sendOk(`/user/${mongoUser.displayname}`, registeredPayment._id.toString()) | |
} | |
}) | |
} | |
} else { | |
const payMongo: MongoCryptoPayment = { | |
privatekey: encPK, | |
address: encAddress, | |
userId: mongoUser._id, | |
cryptoType: payPost.type, | |
status: PaymentStatus.active, | |
type: PaymentType.cryptocurrency, | |
default: isDefault, | |
} | |
col.insertOne(payMongo, (err, result) => { | |
if (err) throw err | |
if (result.insertedCount != 1) { | |
L('Server error') | |
sendFail('DB error') | |
} else { | |
const success = () => { | |
L(`Inserted new card: ${result.insertedId}`) | |
sendOk(`/user/${mongoUser.displayname}`, result.insertedId) | |
} | |
if (isDefault) { | |
const payMongoId = new mongo.ObjectId(result.insertedId) | |
makeDefaultPayment(mongoUser._id, payMongoId, success) | |
} | |
else | |
success() | |
} | |
}) | |
} | |
}) | |
}) | |
} | |
}) | |
} | |
} | |
}) | |
router.delete('/payments/crypto', (req: express.Request, res: express.Response) => { | |
L("delete /user/payments/crypto request from - " + req.ip) | |
const sendBack = (result: OperationResult, errDesc: string) => { | |
const or: OperationResultResponse = { result: result, errDesc: errDesc } | |
res.send(or) | |
} | |
if (!isSessionAuthAlreadyValid(req)) { | |
L('User not logged in') | |
sendBack(OperationResult.error, 'User not logged in') | |
} else { | |
getSessionUser(req, (mongoUser: MongoUser) => { | |
if (!mongoUser) { | |
L('Failed to find user for current active session') | |
sendBack(OperationResult.error, 'Session invalid for user') | |
} else { | |
const paymentId = req.body.paymentId | |
L(`Deleteting payment ${paymentId}`) | |
const mongoId = new mongo.ObjectId(paymentId) | |
getMongoDBCollection('payments', (col) => { | |
col.updateOne({ _id: mongoId }, { $set: { status: PaymentStatus.deleted } }, (err, result) => { | |
if (err) throw err | |
if (result.matchedCount == 1) { | |
L(`Sucesfully deleted ${paymentId}`) | |
getActiveUserPayments(mongoUser._id, (cryptoPayments: MongoCryptoPayment[]) => { | |
let hasDefault = false | |
cryptoPayments.forEach((cryptoPayment) => { | |
if (cryptoPayment.default) | |
hasDefault = true | |
}) | |
if (!hasDefault && cryptoPayments.length > 0) { | |
makeDefaultPayment(mongoUser._id, cryptoPayments[0]._id, (res) => { | |
if (!res) | |
sendBack(OperationResult.error, 'DB server failed to set new default payment') | |
else | |
sendBack(OperationResult.ok, '') | |
}) | |
} | |
else | |
sendBack(OperationResult.ok, '') | |
}) | |
} | |
else { | |
L(`Server error when deleting ${paymentId}`) | |
sendBack(OperationResult.error, 'DB server error') | |
} | |
}) | |
}) | |
} | |
}) | |
} | |
}) | |
export interface MongoCardPayment extends MongoPayment { | |
cardnumber: EncData, | |
name: string, | |
expmonth: string, | |
expyear: string, | |
cvc: EncData, | |
cardType: string, | |
} | |
// router.post('/payments/card', (req: express.Request, res: express.Response) => { | |
// L("post /user/payments/card request from - " + req.ip) | |
// const sendBack = (result: OperationResult, errDesc?: string, redirectUri?: string, newPaymentId?: string) => { | |
// const or: NewPaymentPostResponse = { | |
// result: result, | |
// errDesc: errDesc, | |
// redirectUri: redirectUri, | |
// newPaymentId: newPaymentId, | |
// } | |
// res.send(or) | |
// } | |
// if (!isSessionAuthAlreadyValid(req)) { | |
// L('User not logged in') | |
// sendBack(OperationResult.error, 'User not authenticated') | |
// } else { | |
// const payPost: NewPaymentCardPost = req.body | |
// if (!validateNewPaymentCardPost(payPost)) { | |
// L(`Payment post failed to pass valiation`) | |
// sendBack(OperationResult.error, 'Incorrect post format') | |
// } else { | |
// getSessionUser(req, (mongoUser: MongoUser) => { | |
// if (!mongoUser) { | |
// L('Failed to find user for current active session') | |
// sendBack(OperationResult.error, 'User not found') | |
// } else { | |
// getMongoDBCollection('paymentsCard', (col) => { | |
// const encCard = encrypt(payPost.cardnumber) | |
// col.findOne({ cardnumber: encCard, userId: mongoUser._id }, (err, findMongoPay: MongoCardPayment) => { | |
// if (err) throw err | |
// if (findMongoPay) { | |
// L(`Card ${payPost.cardnumber} is already registered to user`) | |
// if (findMongoPay.status == PaymentStatus.active) | |
// sendBack(OperationResult.error, 'Card is already registered to this user!') | |
// else { | |
// L(`Card was deleted, activating it again`) | |
// col.updateOne({ _id: findMongoPay._id }, { $set: { status: PaymentStatus.active } }, (err, result) => { | |
// if (err) throw err | |
// if (result.matchedCount == 1) { | |
// L(`Re-activated card: ${findMongoPay._id}`) | |
// sendBack(OperationResult.ok, '', `/user/${mongoUser.displayname}`) | |
// } else { | |
// L('Server error') | |
// sendBack(OperationResult.error, 'DB error') | |
// } | |
// }) | |
// } | |
// } else { | |
// const encCVC = encrypt(payPost.cvc) | |
// const payMongo: MongoCardPayment = { | |
// cardnumber: encCard, | |
// name: payPost.name, | |
// expmonth: payPost.expmonth, | |
// expyear: payPost.expyear, | |
// cvc: encCVC, | |
// userId: mongoUser._id, | |
// cardType: valid.number(payPost.cardnumber).card.type, | |
// status: PaymentStatus.active, | |
// type:PaymentType.creditcard, | |
// } | |
// col.insertOne(payMongo, (err, result) => { | |
// if (err) throw err | |
// if (result.insertedCount != 1) { | |
// L('Server error') | |
// sendBack(OperationResult.error, 'DB error') | |
// } else { | |
// L(`Inserted new card: ${result.insertedId}`) | |
// sendBack(OperationResult.ok, '', `/user/${mongoUser.displayname}`, result.insertedId) | |
// } | |
// }) | |
// } | |
// }) | |
// }) | |
// } | |
// }) | |
// } | |
// } | |
// }) | |
// router.delete('/payments/card', (req: express.Request, res: express.Response) => { | |
// L("delete /user/payments/crypto request from - " + req.ip) | |
// const sendBack = (result: OperationResult, errDesc: string) => { | |
// const or: OperationResultResponse = { result: result, errDesc: errDesc } | |
// res.send(or) | |
// } | |
// if (!isSessionAuthAlreadyValid(req)) { | |
// L('User not logged in') | |
// sendBack(OperationResult.error, 'User not logged in') | |
// } else { | |
// getSessionUser(req, (mongoUser: MongoUser) => { | |
// if (!mongoUser) { | |
// L('Failed to find user for current active session') | |
// sendBack(OperationResult.error, 'Session invalid for user') | |
// } else { | |
// const paymentId = req.body.paymentId | |
// L(`Deleteting payment ${paymentId}`) | |
// const mongoId = new mongo.ObjectId(paymentId) | |
// getMongoDBCollection('paymentsCard', (col) => { | |
// col.updateOne({ _id: mongoId }, { | |
// $set: { status: PaymentStatus.deleted } | |
// }, (err, result) => { | |
// if (err) throw err | |
// if (result.matchedCount == 1) { | |
// L(`Sucesfully deleted ${paymentId}`) | |
// sendBack(OperationResult.ok, '') | |
// } | |
// else { | |
// L(`Server error when deleting ${paymentId}`) | |
// sendBack(OperationResult.error, 'DB server error') | |
// } | |
// }) | |
// }) | |
// } | |
// }) | |
// } | |
// }) | |
// function validateNewPaymentCardPost(p: NewPaymentCardPost): boolean { | |
// const cn = checkCardNumber(p) | |
// const ca = checkCardName(p) | |
// const cm = checkCardYear(p) | |
// const cv = checkCVC(p) | |
// return cn && ca && cm && cv | |
// } | |
// function checkCardName(p: NewPaymentCardPost): boolean { | |
// if (p.name === undefined) return false | |
// return valid.cardholderName(p.name).isValid | |
// } | |
// function checkCardNumber(p: NewPaymentCardPost): boolean { | |
// if (!p.cardnumber) return false | |
// return valid.number(p.cardnumber).isValid | |
// } | |
// function checkCardYear(p: NewPaymentCardPost): boolean { | |
// if (!p.expyear || !p.expmonth) return false | |
// return valid.expirationMonth(p.expmonth) && valid.expirationYear(p.expyear) | |
// } | |
// function checkCVC(p: NewPaymentCardPost): boolean { | |
// if (!p.cvc) return false | |
// return valid.cvv(p.cvc) | |
// } | |
// export interface CardPaymentPage { | |
// id: string, | |
// cardnumber: string, | |
// cardImgUri: string, | |
// } | |
function validateNewPaymentCryptoPost(p: NewPaymentCryptoPost): boolean { | |
const wa = checkWalletAddress(p) | |
const ck = checkPrivateKey(p) | |
return wa && ck | |
} | |
export interface CryptoPaymentPage { | |
id: string, | |
address: string, | |
cryptoImgUri: string, | |
default: boolean, | |
} | |
export interface PaymentPage { | |
cryptos: CryptoPaymentPage[], | |
} | |
export function mongoPayments2paymentsPage(cryptoMongoPayments: MongoCryptoPayment[]): PaymentPage { | |
let cryptoPaymentsPage: CryptoPaymentPage[] = [] | |
cryptoMongoPayments.forEach((cryptoMongoPayment: MongoCryptoPayment) => { | |
let cryptoImgUri = '/etherum2.png' | |
let printAddress: string = "" | |
const rawAddress = decrypt(cryptoMongoPayment.address) | |
if (rawAddress.length > 8) { | |
for (let i = 0; i < rawAddress.length - 8; i++) { | |
printAddress += '*' | |
} | |
printAddress += rawAddress.slice(rawAddress.length - 8) | |
printAddress = printAddress.slice(8) | |
} else { | |
printAddress = `****` | |
} | |
let paymentPage: CryptoPaymentPage = { | |
address: printAddress, | |
cryptoImgUri: cryptoImgUri, | |
id: cryptoMongoPayment._id.toString(), | |
default: cryptoMongoPayment.default, | |
} | |
cryptoPaymentsPage.push(paymentPage) | |
}) | |
return { | |
cryptos: cryptoPaymentsPage, | |
} | |
} | |
function checkWalletAddress(p: NewPaymentCryptoPost): boolean { | |
return SharedRegex.walletAddress.test(p.address) | |
} | |
function checkPrivateKey(p: NewPaymentCryptoPost): boolean { | |
return SharedRegex.privateKey.test(p.privateKey) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment