Skip to content

Commit

Permalink
add votes and password routes
Browse files Browse the repository at this point in the history
  • Loading branch information
tevko committed Jan 14, 2025
1 parent 00b3b7c commit 5338611
Show file tree
Hide file tree
Showing 5 changed files with 510 additions and 450 deletions.
200 changes: 200 additions & 0 deletions server/src/routes/password.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
import Session from "../session";
import logger from "../utils/logger";
import fail from "../utils/fail";
import {
queryP as pgQueryP,
queryP_readOnly as pgQueryP_readOnly,
} from "../db/pg-query";
import { generateHashedPassword } from "../auth/password";
import Config from "../config";
import cookies from "../utils/cookies";
import User from "../user";
import emailSenders from "../email/senders";

const sendTextEmail = emailSenders.sendTextEmail;

const getUidForPwResetToken = Session.getUidForPwResetToken;
const clearPwResetToken = Session.clearPwResetToken;
const getServerNameWithProtocol = Config.getServerNameWithProtocol;
const setupPwReset = Session.setupPwReset;
const polisFromAddress = Config.polisFromAddress;
const getUserInfoForUid = User.getUserInfoForUid;

function sendPasswordResetEmail(
uid?: any,
pwresettoken?: any,
serverName?: any,
callback?: { (err: any): void; (arg0?: string): void }
) {
getUserInfoForUid(
uid,
// Argument of type '(err: any, userInfo: { hname: any; email: any; }) => void' is not assignable to parameter of type '(arg0: null, arg1?: undefined) => void'.
// Types of parameters 'userInfo' and 'arg1' are incompatible.
// Type 'undefined' is not assignable to type '{ hname: any; email: any; }'.ts(2345)
// @ts-ignore
function (err: any, userInfo: { hname: any; email: any }) {
if (err) {
return callback?.(err);
}
if (!userInfo) {
return callback?.("missing user info");
}
let body = `Hi ${userInfo.hname},
We have just received a password reset request for ${userInfo.email}
To reset your password, visit this page:
${serverName}/pwreset/${pwresettoken}
"Thank you for using Polis`;

sendTextEmail(
polisFromAddress,
userInfo.email,
"Polis Password Reset",
body
)
.then(function () {
callback?.();
})
.catch(function (err: any) {
logger.error("polis_err_failed_to_email_password_reset_code", err);
callback?.(err);
});
}
);
}

function getUidByEmail(email: string) {
email = email.toLowerCase();
return pgQueryP_readOnly(
"SELECT uid FROM users where LOWER(email) = ($1);",
[email]
// Argument of type '(rows: string | any[]) => any' is not assignable to parameter of type '(value: unknown) => any'.
// Types of parameters 'rows' and 'value' are incompatible.
// Type 'unknown' is not assignable to type 'string | any[]'.
// Type 'unknown' is not assignable to type 'any[]'.ts(2345)
// @ts-ignore
).then(function (rows: string | any[]) {
if (!rows || !rows.length) {
throw new Error("polis_err_no_user_matching_email");
}
return rows[0].uid;
});
}

function handle_POST_auth_password(
req: { p: { pwresettoken: any; newPassword: any } },
res: {
status: (
arg0: number
) => {
(): any;
new (): any;
json: { (arg0: string): void; new (): any };
};
}
) {
let pwresettoken = req.p.pwresettoken;
let newPassword = req.p.newPassword;

getUidForPwResetToken(
pwresettoken,
// Argument of type '(err: any, userParams: { uid?: any; }) => void' is not assignable to parameter of type '(arg0: number | null, arg1?: { uid: any; } | undefined) => void'.
// Types of parameters 'userParams' and 'arg1' are incompatible.
// Type '{ uid: any; } | undefined' is not assignable to type '{ uid?: any; }'.
// Type 'undefined' is not assignable to type '{ uid?: any; }'.ts(2345)
// @ts-ignore
function (err: any, userParams: { uid?: any }) {
if (err) {
fail(
res,
500,
"Password Reset failed. Couldn't find matching pwresettoken.",
err
);
return;
}
let uid = Number(userParams.uid);
generateHashedPassword(
newPassword,
function (err: any, hashedPassword: any) {
return pgQueryP(
"insert into jianiuevyew (uid, pwhash) values " +
"($1, $2) on conflict (uid) " +
"do update set pwhash = excluded.pwhash;",
[uid, hashedPassword]
).then(
(rows: any) => {
res.status(200).json("Password reset successful.");
clearPwResetToken(pwresettoken, function (err: any) {
if (err) {
logger.error("polis_err_auth_pwresettoken_clear_fail", err);
}
});
},
(err: any) => {
fail(res, 500, "Couldn't reset password.", err);
}
);
}
);
}
);
}

function handle_POST_auth_pwresettoken(
req: { p: { email: any } },
res: {
status: (
arg0: number
) => {
(): any;
new (): any;
json: { (arg0: string): void; new (): any };
};
}
) {
let email = req.p.email;

let server = getServerNameWithProtocol(req);

// let's clear the cookies here, in case something is borked.
cookies.clearCookies(req, res);

function finish() {
res.status(200).json("Password reset email sent, please check your email.");
}

getUidByEmail(email).then(
function (uid?: any) {
setupPwReset(uid, function (err: any, pwresettoken: any) {
sendPasswordResetEmail(uid, pwresettoken, server, function (err: any) {
if (err) {
fail(res, 500, "Error: Couldn't send password reset email.", err);
return;
}
finish();
});
});
},
function () {
sendPasswordResetEmailFailure(email, server);
finish();
}
);
}

function sendPasswordResetEmailFailure(email: any, server: any) {
let body = `We were unable to find a pol.is account registered with the email address: ${email}
You may have used another email address to create your account.
If you need to create a new account, you can do that here ${server}/home
Feel free to reply to this email if you need help.`;

return sendTextEmail(polisFromAddress, email, "Password Reset Failed", body);
}

export { handle_POST_auth_password, handle_POST_auth_pwresettoken };
144 changes: 144 additions & 0 deletions server/src/routes/votes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import _ from "underscore";
import {
query as pgQuery,
query_readOnly as pgQuery_readOnly,
queryP_readOnly as pgQueryP_readOnly,
} from "../db/pg-query";
import { isDuplicateKey } from "../utils/common";
import logger from "../utils/logger";
import Conversation from "../conversation";
import SQL from "../db/sql";

const isXidWhitelisted = Conversation.isXidWhitelisted;
const sql_votes_latest_unique = SQL.sql_votes_latest_unique;

function doVotesPost(
uid?: any,
pid?: any,
conv?: { zid: any },
tid?: any,
voteType?: any,
weight?: number,
high_priority?: boolean
) {
let zid = conv?.zid;
weight = weight || 0;
let weight_x_32767 = Math.trunc(weight * 32767); // weight is stored as a SMALLINT, so convert from a [-1,1] float to [-32767,32767] int
return new Promise(function (
resolve: (arg0: { conv: any; vote: any }) => void,
reject: (arg0: string) => void
) {
let query =
"INSERT INTO votes (pid, zid, tid, vote, weight_x_32767, high_priority, created) VALUES ($1, $2, $3, $4, $5, $6, default) RETURNING *;";
let params = [pid, zid, tid, voteType, weight_x_32767, high_priority];
pgQuery(query, params, function (err: any, result: { rows: any[] }) {
if (err) {
if (isDuplicateKey(err)) {
reject("polis_err_vote_duplicate");
} else {
logger.error("polis_err_vote_other", err);
reject("polis_err_vote_other");
}
return;
}

const vote = result.rows[0];

resolve({
conv: conv,
vote: vote,
});
});
});
}

function votesPost(
uid?: any,
pid?: any,
zid?: any,
tid?: any,
xid?: any,
voteType?: any,
weight?: number,
high_priority?: boolean
) {
return (
pgQueryP_readOnly("select * from conversations where zid = ($1);", [zid])
// Argument of type '(rows: string | any[]) => any' is not assignable to parameter of type '(value: unknown) => any'.
// Types of parameters 'rows' and 'value' are incompatible.
// Type 'unknown' is not assignable to type 'string | any[]'.
// Type 'unknown' is not assignable to type 'any[]'.ts(2345)
// @ts-ignore
.then(function (rows: string | any[]) {
if (!rows || !rows.length) {
throw "polis_err_unknown_conversation";
}
const conv = rows[0];
if (!conv.is_active) {
throw "polis_err_conversation_is_closed";
}
if (conv.use_xid_whitelist) {
return isXidWhitelisted(conv.owner, xid).then(
(is_whitelisted: boolean) => {
if (is_whitelisted) {
return conv;
} else {
throw "polis_err_xid_not_whitelisted";
}
}
);
}
return conv;
})
.then(function (conv: any) {
return doVotesPost(
uid,
pid,
conv,
tid,
voteType,
weight,
high_priority
);
})
);
}

function getVotesForSingleParticipant(p: { pid: any }) {
if (_.isUndefined(p.pid)) {
return Promise.resolve([]);
}
return votesGet(p);
}

function votesGet(p: { zid?: any; pid?: any; tid?: any }) {
// 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009)
// @ts-ignore
return new MPromise(
"votesGet",
function (resolve: (arg0: any) => void, reject: (arg0: any) => void) {
let q = sql_votes_latest_unique
.select(sql_votes_latest_unique.star())
.where(sql_votes_latest_unique.zid.equals(p.zid));

if (!_.isUndefined(p.pid)) {
q = q.where(sql_votes_latest_unique.pid.equals(p.pid));
}
if (!_.isUndefined(p.tid)) {
q = q.where(sql_votes_latest_unique.tid.equals(p.tid));
}
pgQuery_readOnly(
q.toString(),
function (err: any, results: { rows: any }) {
if (err) {
reject(err);
} else {
resolve(results.rows);
}
}
);
}
);
}

export { votesGet, getVotesForSingleParticipant, votesPost, doVotesPost };
Loading

0 comments on commit 5338611

Please sign in to comment.