Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comments to understand functions in the backend #57

Merged
merged 7 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 46 additions & 13 deletions server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

"use strict";

import akismetLib from "akismet";
import akismetLib from "akismet"; // spam protection for user-submitted text
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a comment block at the beginning of your file to explain the purpose and key features of imported libraries is a good practice, especially when those libraries are not immediately obvious from the code itself or are less commonly used.

Here's how you might structure such a comment block at the beginning of the file, using the akismet example:

/**
 * @file This file contains the core logic for [brief description of the file's purpose].
 *
 * Dependencies:
 *  - `akismet`: This library is used for spam protection.  It provides functionality to check if user-submitted text is spam.  See [link to library documentation] for details on its API and usage.  Specifically, we're using it to [explain how you're using it, e.g., "check comments before posting"].
 *  - [Other library]: [brief explanation of its purpose and how it's used in this file].
 *
 *  Note: Ensure that the Akismet API key is correctly configured in the environment variables.  See [link to relevant documentation or configuration file].
 */

import { Client as AkismetClient } from "akismet";

// ... rest of your code ...

import AWS from "aws-sdk";
import badwords from "badwords/object";
import { Promise as BluebirdPromise } from "bluebird";
Expand Down Expand Up @@ -234,6 +234,7 @@ function haltOnTimeout(req: { timedout: any }, res: any, next: () => void) {
}
}

// checks if a property (name) exists in a source object and copies that property to a dest object
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To enable IDEs recognize the comment and shows the comment when developer hover on the function where it is been used, the following syntax would be better:

/**
 * Checks if a property exists in a source object and copies it to a destination object.
 *
 * @param name - The name of the property to check and copy.
 * @param source - The source object containing the property.
 * @param dest - The destination object to copy the property to.  If undefined, a new object will be created.
 * @returns The destination object with the property copied if it exists in the source object. Returns undefined if the source object is undefined.
 * @throws {Error} If the source object is not an object or the destination object is not an object or undefined.
 **/

More about TSDoc specification. https://tsdoc.org/

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second this!

function ifDefinedSet(
name: string,
source: { [x: string]: any },
Expand Down Expand Up @@ -297,13 +298,15 @@ function hasAuthToken(req: { cookies: { [x: string]: any } }) {
return !!req.cookies[COOKIES.TOKEN];
}

// returns uid associated with provided apikey
function getUidForApiKey(apikey: any) {
return pgQueryP_readOnly_wRetryIfEmpty(
"select uid from apikeysndvweifu WHERE apikey = ($1);",
[apikey]
);
}
// http://en.wikipedia.org/wiki/Basic_access_authentication#Client_side
// parses the apikey (username) from the header and calls doApiKeyAuth with it
function doApiKeyBasicAuth(
assigner: any,
header: string,
Expand All @@ -321,6 +324,7 @@ function doApiKeyBasicAuth(
return doApiKeyAuth(assigner, apikey, isOptional, req, res, next);
}

// verifies that apikey can be found in the apikeysndvweifu table and assigns the associated uid to req object
function doApiKeyAuth(
assigner: (arg0: any, arg1: string, arg2: number) => void,
apikey: string,
Expand Down Expand Up @@ -374,11 +378,12 @@ const getXidRecordByXidOwnerId = User.getXidRecordByXidOwnerId;
// });
// }

// given an apikey and xid, retrieves the associated uid and sets it, along with xid, owner_id, and org_id, in the req object
function doXidApiKeyAuth(
assigner: (arg0: any, arg1: string, arg2: number) => void,
apikey: any,
xid: any,
isOptional: any,
isOptional: any, // whether
req: AuthRequest,
res: { status: (arg0: number) => void },
next: {
Expand All @@ -387,7 +392,7 @@ function doXidApiKeyAuth(
(arg0?: string | undefined): void;
}
) {
getUidForApiKey(apikey)
getUidForApiKey(apikey) // returns uid associated with the provided apikey from apikeysndvweifu table
.then(
// Argument of type '(rows: string | any[]) => Promise<void> | undefined' is not assignable to parameter of type '(value: unknown) => void | PromiseLike<void | undefined> | undefined'.
// Types of parameters 'rows' and 'value' are incompatible.
Expand Down Expand Up @@ -425,7 +430,7 @@ function doXidApiKeyAuth(
}
}
let uidForCurrentUser = Number(rows[0].uid);
assigner(req, "uid", uidForCurrentUser);
assigner(req, "uid", uidForCurrentUser); // the uid associated with the owner and xid in the xids table
assigner(req, "xid", xid);
assigner(req, "owner_uid", uidForApiKey);
assigner(req, "org_id", uidForApiKey);
Expand All @@ -444,6 +449,9 @@ function doXidApiKeyAuth(
next("polis_err_auth_misc_23423");
});
}

// checks that the auth_token in req.headers is associated with the uid value in req.body as per the auth_tokens table
// runs the assigner function with the found uid and calls next - assigns uid to req object?
function doHeaderAuth(
assigner: (arg0: any, arg1: string, arg2: number) => void,
isOptional: any,
Expand All @@ -461,7 +469,7 @@ function doHeaderAuth(
next("polis_err_auth_no_such_token");
return;
}
if (req.body.uid && req.body.uid !== uid) {
if (req.body.uid && req.body.uid !== uid) { // compares the uid retrieved based on the token to the req.body's uid
res.status(401);
next("polis_err_auth_mismatch_uid");
return;
Expand Down Expand Up @@ -538,6 +546,7 @@ function initializePolisHelpers() {
const getPidPromise = User.getPidPromise;
const getPidForParticipant = User.getPidForParticipant;

// inserts into permanentCookieZidJoin
function recordPermanentCookieZidJoin(permanentCookieToken: any, zid: any) {
function doInsert() {
return pgQueryP(
Expand Down Expand Up @@ -831,17 +840,20 @@ function initializePolisHelpers() {
// });
// }

// given an xid and conversation_id (zinvite?), verifies that the xid is whitelisted, and assigns the associated uid of that xid to the req object
// calls onDone regardless of auth outcome
function doXidConversationIdAuth(
assigner: (arg0: any, arg1: string, arg2: number) => void,
xid: any,
conversation_id: any,
isOptional: any,
isOptional: any, // whether passing the auth check is optional
req: AuthRequest,
res: { status: (arg0: number) => void },
onDone: { (err: any): void; (arg0?: string): void }
) {
return getConversationInfoByConversationId(conversation_id)
.then((conv: { org_id: any; zid: any }) => {
//
return getXidRecordByXidOwnerId(
xid,
conv.org_id,
Expand All @@ -856,6 +868,7 @@ function initializePolisHelpers() {
// Type 'unknown' is not assignable to type 'any[]'.ts(2345)
// @ts-ignore
).then((rows: string | any[]) => {
// if conversation requires a whitelist check and the xid is not whitelisted
if (!rows || !rows.length) {
if (isOptional) {
return onDone();
Expand All @@ -875,7 +888,11 @@ function initializePolisHelpers() {
onDone(err);
});
}

// returns a middleware that after authenticating the current user, uses the passed assigner to assign the user's uid to the req object
function _auth(assigner: any, isOptional: boolean) {

// looks for key property in the body, headers, and query
function getKey(
req: {
body: Body;
Expand All @@ -887,6 +904,7 @@ function initializePolisHelpers() {
return req.body[key] || req?.headers?.[key] || req?.query?.[key];
}

// returns a Promise that that when resolved (as a a result of auth success), assigns the uid of the current user to the req object
function doAuth(
req: {
cookies: { [x: string]: any };
Expand All @@ -897,7 +915,7 @@ function initializePolisHelpers() {
res: { status: (arg0: number) => void }
) {
//var token = req.body.token;
let token = req.cookies[COOKIES.TOKEN];
let token = req.cookies[COOKIES.TOKEN]; // currently req.cookies['token2']
let xPolisToken = req?.headers?.["x-polis"];

return new Promise(function (
Expand All @@ -915,8 +933,8 @@ function initializePolisHelpers() {
}
if (xPolisToken) {
logger.info("authtype: doHeaderAuth");
doHeaderAuth(assigner, isOptional, req, res, onDone);
} else if (getKey(req, "polisApiKey") && getKey(req, "ownerXid")) {
doHeaderAuth(assigner, isOptional, req, res, onDone); // runs assigner with the uid associated with xPolisToken and calls onDone after
} else if (getKey(req, "polisApiKey") && getKey(req, "ownerXid")) { // if poliApiKey and ownerXid can be found in the body, headers or query properties of req
doXidApiKeyAuth(
assigner,
getKey(req, "polisApiKey"),
Expand Down Expand Up @@ -982,12 +1000,12 @@ function initializePolisHelpers() {
res,
onDone
);
} else if (req.body.agid) {
} else if (req.body.agid) { // create a new user, ...
// Auto Gen user ID
createDummyUser()
.then(
function (uid?: any) {
let shouldAddCookies = _.isUndefined(req.body.xid);
let shouldAddCookies = _.isUndefined(req.body.xid); // if there is no xid in req.body, shouldAddCookies is true
if (!shouldAddCookies) {
req.p = req.p || {};
req.p.uid = uid;
Expand Down Expand Up @@ -1025,6 +1043,7 @@ function initializePolisHelpers() {
}
});
}

return function (
req: any,
res: { status: (arg0: number) => void },
Expand Down Expand Up @@ -1089,6 +1108,7 @@ function initializePolisHelpers() {
return _auth(assigner, false);
}

// setting the so-called auto gen id in req.body
function enableAgid(req: { body: Body }, res: any, next: () => void) {
req.body.agid = 1;
next();
Expand Down Expand Up @@ -1679,7 +1699,8 @@ function initializePolisHelpers() {
});
});
}


// redirect to about page is request has zid but no conversation_id
function redirectIfHasZidButNoConversationId(
req: { body: { zid: any; conversation_id: any }; headers?: any },
res: {
Expand Down Expand Up @@ -1984,6 +2005,7 @@ function initializePolisHelpers() {
]
);
}

if (
Config.runPeriodicExportTests &&
!devMode &&
Expand Down Expand Up @@ -2031,6 +2053,7 @@ function initializePolisHelpers() {
};
setInterval(runExportTest, 6 * 60 * 60 * 1000); // every 6 hours
}

function handle_GET_dataExport(
req: { p: { uid?: any; zid: any; unixTimestamp: number; format: any } },
res: { json: (arg0: {}) => void }
Expand All @@ -2056,6 +2079,7 @@ function initializePolisHelpers() {
fail(res, 500, "polis_err_data_export123b", err);
});
}

function handle_GET_dataExport_results(
req: { p: { filename: string } },
res: { redirect: (arg0: any) => void }
Expand Down Expand Up @@ -2261,6 +2285,7 @@ function initializePolisHelpers() {
}
});
}

function handle_GET_bidToPid(
req: { p: { zid: any; math_tick: any } },
res: {
Expand All @@ -2285,6 +2310,7 @@ function initializePolisHelpers() {
);
}

// given a zid, get all the pids, xids involved in the conversation
function getXids(zid: any) {
// 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009)
// @ts-ignore
Expand All @@ -2307,6 +2333,9 @@ function initializePolisHelpers() {
}
);
}

// handler function
// if the uid in the req object is the same as the zid's owner, retrieve and return the xids associated with the zid
function handle_GET_xids(
req: { p: { uid?: any; zid: any } },
res: {
Expand All @@ -2330,14 +2359,15 @@ function initializePolisHelpers() {
}
);
} else {
fail(res, 403, "polis_err_get_xids_not_authorized");
fail(res, 403, "polis_err_get_xids_not_authorized"); // uid of the req object is not the zid owner
}
},
function (err: any) {
fail(res, 500, "polis_err_get_xids", err);
}
);
}

function handle_POST_xidWhitelist(
req: { p: { xid_whitelist: any; uid?: any } },
res: {
Expand Down Expand Up @@ -2676,6 +2706,8 @@ Feel free to reply to this email if you need help.`;
JSON.stringify(res?._headers?.["set-cookie"])
);
}

// verifies that the uid in req.body is associated with the token found in the cookies and then assigns it in the req object
function doCookieAuth(
assigner: (arg0: any, arg1: string, arg2: number) => void,
isOptional: any,
Expand Down Expand Up @@ -3725,6 +3757,7 @@ Feel free to reply to this email if you need help.`;
);
}

// given a zid and uid, checks if the uid is the same as the conversation owner's uid
function isOwner(zid: any, uid: string) {
return getConversationInfo(zid).then(function (info: any) {
return info.owner === uid;
Expand Down
1 change: 1 addition & 0 deletions server/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const userTokenCache = new LruCache({
max: 9000,
});

// runs the provided callback with the uid associated with the provided token in the auth_tokens table
function getUserInfoForSessionToken(
sessionToken: unknown,
res: any,
Expand Down
6 changes: 6 additions & 0 deletions server/src/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ function getFacebookInfo(uids: any[]) {
);
}

// insert a new entry into the `users` table and return the value of uid for the new entry
function createDummyUser() {
// (parameter) resolve: (arg0: any) => void
// 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009)
Expand Down Expand Up @@ -300,6 +301,8 @@ function getSocialInfoForUsers(uids: any[], zid: any) {
);
}

// an owner with an xid is passed in, returns the matching entry(s?) from `xids` (that includes the corresponding uid)
// if no xid entry is found, does some optional checks if caller chooses to determine if an entry into xids
function getXidRecordByXidOwnerId(
xid: any,
owner: any,
Expand All @@ -322,12 +325,14 @@ function getXidRecordByXidOwnerId(
// Type 'unknown' is not assignable to type 'any[]'.ts(2345)
// @ts-ignore
.then(function (rows: string | any[]) {
// if an `xids` table record with the provided xid and owner id cannot be found
if (!rows || !rows.length) {
logger.warn("getXidRecordByXidOwnerId: no xInfo yet");
if (!createIfMissing) {
return null;
}

// if provided zid, and if conversation is configured to use xid_whitelist, returns true if the owner id is whitelisted
var shouldCreateXidEntryPromise = !zid_optional
? Promise.resolve(true)
: Conversation.getConversationInfo(zid_optional).then(
Expand All @@ -338,6 +343,7 @@ function getXidRecordByXidOwnerId(
}
);

// create a new user (in `users` table) and then a new entry in the `xids` table with the uid from the user creation process
return shouldCreateXidEntryPromise.then((should: any) => {
if (!should) {
return null;
Expand Down
Loading