mirror of
https://github.com/wassname/talk.git
synced 2026-08-11 11:27:10 +08:00
[CORL-678] Transition to eslint (#2634)
* chore: setup eslint * chore: tslint checks with types & check for import order * chore: complete eslint transition * fix: tests * fix: linting after rebase, faster lint for lint-staged * chore: remove line * fix: lint rules * feat: add a11y linter and fix errors * fix: tests
This commit is contained in:
@@ -14,7 +14,7 @@ export function getHostname(req: IncomingMessage) {
|
||||
}
|
||||
|
||||
// IPv6 literal support
|
||||
const offset = host[0] === "[" ? host.indexOf("]") + 1 : 0;
|
||||
const offset = host.startsWith("[") ? host.indexOf("]") + 1 : 0;
|
||||
const index = host.indexOf(":", offset);
|
||||
|
||||
return index !== -1 ? host.substring(0, index) : host;
|
||||
|
||||
@@ -104,7 +104,7 @@ export const listenAndServe = (
|
||||
app: Express,
|
||||
port: number
|
||||
): Promise<http.Server> =>
|
||||
new Promise(async resolve => {
|
||||
new Promise(resolve => {
|
||||
// Listen on the designated port.
|
||||
const httpServer = app.listen(port, () => resolve(httpServer));
|
||||
});
|
||||
|
||||
@@ -20,8 +20,8 @@ const wrapError = (err: Error) =>
|
||||
* API response.
|
||||
*
|
||||
* @param err the CoralError that should be serialized
|
||||
* @param req the request
|
||||
* @param bundles the translation bundles
|
||||
* @param tenant the optional tenant to use when selecting the language
|
||||
*/
|
||||
const serializeError = (err: CoralError, req: Request, bundles?: I18n) => {
|
||||
// Get the translation bundle.
|
||||
|
||||
@@ -201,8 +201,8 @@ export async function handleOAuth2Callback(
|
||||
|
||||
// Send back the details!
|
||||
res.redirect(path + `#accessToken=${token}`);
|
||||
} catch (err) {
|
||||
res.redirect(path + `#error=${encodeURIComponent(err.message)}`);
|
||||
} catch (e) {
|
||||
res.redirect(path + `#error=${encodeURIComponent(e.message)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,8 +227,8 @@ export const wrapOAuth2Authn = (
|
||||
async (err: Error | null, user: User | null) => {
|
||||
try {
|
||||
await handleOAuth2Callback(err, user, signingConfig, req, res);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
}
|
||||
}
|
||||
)(req, res, next);
|
||||
@@ -262,8 +262,8 @@ export const wrapAuthn = (
|
||||
try {
|
||||
// Pass the login off to be signed.
|
||||
await handleSuccessfulLogin(user, signingConfig, req, res, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
}
|
||||
}
|
||||
)(req, res, next);
|
||||
|
||||
@@ -254,8 +254,8 @@ export function findOrCreateOIDCUserWithToken(
|
||||
now
|
||||
);
|
||||
return resolve(user);
|
||||
} catch (err) {
|
||||
return reject(err);
|
||||
} catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// tslint:disable:max-classes-per-file
|
||||
/* eslint-disable max-classes-per-file */
|
||||
|
||||
import { Redis } from "ioredis";
|
||||
import ms from "ms";
|
||||
|
||||
@@ -22,7 +22,7 @@ function wrapPath(
|
||||
{ passport }: Pick<RouterOptions, "passport">,
|
||||
router: express.Router,
|
||||
strategy: string,
|
||||
path: string = `/${strategy}`
|
||||
path = `/${strategy}`
|
||||
) {
|
||||
const handler = wrapOAuth2Authn(passport, app.signingConfig, strategy);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Tenant } from "coral-server/models/tenant";
|
||||
import { Request } from "coral-server/types/express";
|
||||
import { URL } from "url";
|
||||
|
||||
export function reconstructURL(req: Request, path: string = "/"): string {
|
||||
export function reconstructURL(req: Request, path = "/"): string {
|
||||
const scheme = req.secure ? "https" : "http";
|
||||
const host = req.get("host");
|
||||
const base = `${scheme}://${host}`;
|
||||
@@ -19,7 +19,7 @@ export function reconstructURL(req: Request, path: string = "/"): string {
|
||||
export function constructTenantURL(
|
||||
config: Config,
|
||||
tenant: Pick<Tenant, "domain">,
|
||||
path: string = "/"
|
||||
path = "/"
|
||||
): string {
|
||||
let url: URL = new URL(path, `https://${tenant.domain}`);
|
||||
if (config.get("env") === "development") {
|
||||
@@ -60,10 +60,7 @@ export function getOrigin(url: string) {
|
||||
export function prefixSchemeIfRequired(secure: boolean, url: string) {
|
||||
if (doesRequireSchemePrefixing(url)) {
|
||||
return (
|
||||
"http" +
|
||||
(secure ? "s" : "") +
|
||||
(url.indexOf("//") === -1 ? "://" : ":") +
|
||||
url
|
||||
"http" + (secure ? "s" : "") + (!url.includes("//") ? "://" : ":") + url
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ const deleteScheduledAccounts: ScheduledJobCommand<Options> = async ({
|
||||
for await (const tenant of tenantCache) {
|
||||
log = log.child({ tenantID: tenant.id }, true);
|
||||
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const now = new Date();
|
||||
const user = await retrieveUserScheduledForDeletion(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// tslint:disable:max-classes-per-file
|
||||
/* eslint-disable max-classes-per-file */
|
||||
|
||||
import { FluentBundle } from "fluent/compat";
|
||||
import { MongoError } from "mongodb";
|
||||
|
||||
@@ -17,7 +17,7 @@ export default new GraphQLScalarType({
|
||||
},
|
||||
parseLiteral(ast) {
|
||||
switch (ast.kind) {
|
||||
case Kind.STRING:
|
||||
case Kind.STRING: {
|
||||
// This handles an empty string.
|
||||
if (ast.value && ast.value.length === 0) {
|
||||
return null;
|
||||
@@ -29,6 +29,7 @@ export default new GraphQLScalarType({
|
||||
}
|
||||
|
||||
return date.toJSDate();
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ export type Publisher = (input: SUBSCRIPTION_INPUT) => Promise<void>;
|
||||
* over the pubsub broker to facilitate live updates and notifications.
|
||||
*
|
||||
* @param pubsub the pubsub broker to be used to facilitate the publish action
|
||||
* @param notifier
|
||||
* @param tenantID the ID of the Tenant where the event will be published with
|
||||
* @param clientID the ID of the client to de-duplicate mutation responses
|
||||
*/
|
||||
|
||||
@@ -154,13 +154,14 @@ export function onConnect(options: OnConnectOptions): OnConnectFn {
|
||||
}
|
||||
|
||||
if (!(err instanceof CoralError)) {
|
||||
// eslint-disable-next-line no-ex-assign
|
||||
err = new InternalError(err, "could not setup websocket connection");
|
||||
}
|
||||
const { message } = err.serializeExtensions(
|
||||
options.i18n.getDefaultBundle()
|
||||
);
|
||||
|
||||
throw { message };
|
||||
throw new Error(message);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -89,10 +89,10 @@ class Server {
|
||||
private tenantCache: TenantCache;
|
||||
|
||||
// connected when true, indicates that `connect()` was already called.
|
||||
private connected: boolean = false;
|
||||
private connected = false;
|
||||
|
||||
// processing when true, indicates that `process()` was already called.
|
||||
private processing: boolean = false;
|
||||
private processing = false;
|
||||
|
||||
// i18n is the server reference to the i18n framework.
|
||||
private i18n: I18n;
|
||||
|
||||
@@ -25,7 +25,7 @@ export class SecretStream extends Transform {
|
||||
this.push(SecretStream.replace(JSON.stringify(chunk)));
|
||||
}
|
||||
} catch (err) {
|
||||
// tslint:disable-next-line:no-console
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
|
||||
@@ -275,6 +275,20 @@ export async function createActions(
|
||||
|
||||
export type CommentActionConnectionInput = ConnectionInput<CommentAction>;
|
||||
|
||||
async function retrieveConnection(
|
||||
input: CommentActionConnectionInput,
|
||||
query: Query<CommentAction>
|
||||
): Promise<Readonly<Connection<Readonly<CommentAction>>>> {
|
||||
// Apply the pagination arguments to the query.
|
||||
query.orderBy({ createdAt: -1 });
|
||||
if (input.after) {
|
||||
query.where({ createdAt: { $lt: input.after as Date } });
|
||||
}
|
||||
|
||||
// Return a connection.
|
||||
return resolveConnection(query, input, action => action.createdAt);
|
||||
}
|
||||
|
||||
export async function retrieveCommentActionConnection(
|
||||
mongo: Db,
|
||||
tenantID: string,
|
||||
@@ -291,20 +305,6 @@ export async function retrieveCommentActionConnection(
|
||||
return retrieveConnection(input, query);
|
||||
}
|
||||
|
||||
async function retrieveConnection(
|
||||
input: CommentActionConnectionInput,
|
||||
query: Query<CommentAction>
|
||||
): Promise<Readonly<Connection<Readonly<CommentAction>>>> {
|
||||
// Apply the pagination arguments to the query.
|
||||
query.orderBy({ createdAt: -1 });
|
||||
if (input.after) {
|
||||
query.where({ createdAt: { $lt: input.after as Date } });
|
||||
}
|
||||
|
||||
// Return a connection.
|
||||
return resolveConnection(query, input, action => action.createdAt);
|
||||
}
|
||||
|
||||
export async function retrieveUserAction(
|
||||
mongo: Db,
|
||||
tenantID: string,
|
||||
@@ -330,7 +330,7 @@ export async function retrieveManyUserActionPresence(
|
||||
userID: string | null,
|
||||
commentIDs: string[]
|
||||
): Promise<GQLActionPresence[]> {
|
||||
const cursor = await collection(mongo).find(
|
||||
const cursor = collection(mongo).find(
|
||||
{
|
||||
tenantID,
|
||||
userID,
|
||||
@@ -505,10 +505,10 @@ interface DecodedActionCountKey {
|
||||
* actionType and reason.
|
||||
*/
|
||||
function decodeActionCountKey(key: string): DecodedActionCountKey | null {
|
||||
let actionType: string = "";
|
||||
let reason: string = "";
|
||||
let actionType = "";
|
||||
let reason = "";
|
||||
|
||||
if (key.indexOf(ACTION_COUNT_JOIN_CHAR) >= 0) {
|
||||
if (key.includes(ACTION_COUNT_JOIN_CHAR)) {
|
||||
const keys = key.split(ACTION_COUNT_JOIN_CHAR);
|
||||
if (keys.length !== 2) {
|
||||
throw new Error(
|
||||
@@ -651,7 +651,7 @@ function incrementActionCounts(
|
||||
actionCounts: ActionCounts,
|
||||
actionType: ACTION_TYPE,
|
||||
reason: GQLCOMMENT_FLAG_REASON | undefined,
|
||||
count: number = 1
|
||||
count = 1
|
||||
) {
|
||||
switch (actionType) {
|
||||
case ACTION_TYPE.REACTION:
|
||||
|
||||
@@ -93,7 +93,7 @@ export async function retrieveCommentModerationActions(
|
||||
tenantID: string,
|
||||
filter: CommentModerationActionFilter
|
||||
) {
|
||||
const result = await collection(mongo).find({
|
||||
const result = collection(mongo).find({
|
||||
tenantID,
|
||||
...filter,
|
||||
});
|
||||
|
||||
@@ -376,7 +376,7 @@ export async function retrieveManyComments(
|
||||
tenantID: string,
|
||||
ids: string[]
|
||||
) {
|
||||
const cursor = await collection(mongo).find({
|
||||
const cursor = collection(mongo).find({
|
||||
id: {
|
||||
$in: ids,
|
||||
},
|
||||
@@ -941,7 +941,7 @@ export async function retrieveStoryCommentTagCounts(
|
||||
const startTime = performanceNow();
|
||||
|
||||
// Load the counts from the database for this particular tag query.
|
||||
const cursor = await collection<{
|
||||
const cursor = collection<{
|
||||
_id: { tag: GQLTAG; storyID: string };
|
||||
total: number;
|
||||
}>(mongo).aggregate([
|
||||
@@ -994,7 +994,7 @@ export async function retrieveManyRecentStatusCounts(
|
||||
authorIDs: string[]
|
||||
) {
|
||||
// Get all the statuses for the given date stamp.
|
||||
const cursor = await collection<{
|
||||
const cursor = collection<{
|
||||
_id: {
|
||||
status: GQLCOMMENT_STATUS;
|
||||
authorID: string;
|
||||
|
||||
@@ -84,7 +84,7 @@ export default class Query<T> {
|
||||
"executing query"
|
||||
);
|
||||
|
||||
let cursor = await this.collection.find(this.filter);
|
||||
let cursor = this.collection.find(this.filter);
|
||||
|
||||
if (this.limit) {
|
||||
// Apply a limit if it exists.
|
||||
|
||||
@@ -89,7 +89,7 @@ export async function failMigration(mongo: Db, id: number, now = new Date()) {
|
||||
}
|
||||
|
||||
export async function retrieveAllMigrationRecords(mongo: Db) {
|
||||
const cursor = await collection(mongo)
|
||||
const cursor = collection(mongo)
|
||||
.find({})
|
||||
.sort({ id: 1 });
|
||||
return cursor.toArray();
|
||||
|
||||
@@ -61,7 +61,7 @@ export async function primeQueries(
|
||||
}
|
||||
|
||||
export async function getQueries(mongo: Db, ids: string[]) {
|
||||
const cursor = await collection(mongo).find({ id: { $in: ids } });
|
||||
const cursor = collection(mongo).find({ id: { $in: ids } });
|
||||
const queries = await cursor.toArray();
|
||||
return ids.map(id => queries.find(query => query.id === id) || null);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ export async function recalculateSharedModerationQueueQueueCounts(
|
||||
await redis.del(key, freshKey);
|
||||
|
||||
// Fetch all the moderation queue counts.
|
||||
const queueResults = await collection<{
|
||||
const queueResults = collection<{
|
||||
_id: string;
|
||||
total: number;
|
||||
}>(mongo).aggregate([
|
||||
@@ -142,7 +142,7 @@ export async function recalculateSharedModerationQueueTotalCounts(
|
||||
await redis.del(key, freshKey);
|
||||
|
||||
// Fetch all the totals for the moderation queues.
|
||||
const totalResults = await collection<{
|
||||
const totalResults = collection<{
|
||||
total: number;
|
||||
}>(mongo).aggregate([
|
||||
{
|
||||
@@ -197,7 +197,7 @@ export async function recalculateSharedStatusCommentCounts(
|
||||
await redis.del(key, freshKey);
|
||||
|
||||
// Fetch all the comments of each status.
|
||||
const statusResults = await collection<{
|
||||
const statusResults = collection<{
|
||||
_id: string;
|
||||
total: number;
|
||||
}>(mongo).aggregate([
|
||||
@@ -271,7 +271,7 @@ export async function recalculateSharedActionCommentCounts(
|
||||
await redis.del(key, freshKey);
|
||||
|
||||
// Fetch all the comments of each status.
|
||||
const actionResults = await collection<{
|
||||
const actionResults = collection<{
|
||||
_id: string;
|
||||
total: number;
|
||||
}>(mongo).aggregate([
|
||||
|
||||
@@ -258,7 +258,7 @@ export async function retrieveManyStories(
|
||||
tenantID: string,
|
||||
ids: string[]
|
||||
) {
|
||||
const cursor = await collection(mongo).find({
|
||||
const cursor = collection(mongo).find({
|
||||
id: { $in: ids },
|
||||
tenantID,
|
||||
});
|
||||
@@ -273,7 +273,7 @@ export async function retrieveManyStoriesByURL(
|
||||
tenantID: string,
|
||||
urls: string[]
|
||||
) {
|
||||
const cursor = await collection(mongo).find({
|
||||
const cursor = collection(mongo).find({
|
||||
url: { $in: urls },
|
||||
tenantID,
|
||||
});
|
||||
|
||||
@@ -212,7 +212,7 @@ export async function retrieveTenant(mongo: Db, id: string) {
|
||||
}
|
||||
|
||||
export async function retrieveManyTenants(mongo: Db, ids: string[]) {
|
||||
const cursor = await collection(mongo).find({
|
||||
const cursor = collection(mongo).find({
|
||||
id: {
|
||||
$in: ids,
|
||||
},
|
||||
@@ -227,7 +227,7 @@ export async function retrieveManyTenantsByDomain(
|
||||
mongo: Db,
|
||||
domains: string[]
|
||||
) {
|
||||
const cursor = await collection(mongo).find({
|
||||
const cursor = collection(mongo).find({
|
||||
domain: {
|
||||
$in: domains,
|
||||
},
|
||||
|
||||
@@ -523,11 +523,12 @@ async function findOrCreateUserInput(
|
||||
|
||||
// Mutate the profiles to ensure we mask handle any secrets.
|
||||
switch (profile.type) {
|
||||
case "local":
|
||||
case "local": {
|
||||
// Hash the user's password with bcrypt.
|
||||
const password = await hashPassword(profile.password);
|
||||
defaults.profiles.push({ ...profile, password });
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Push the profile onto the User.
|
||||
defaults.profiles.push(profile);
|
||||
@@ -626,7 +627,7 @@ export async function retrieveManyUsers(
|
||||
tenantID: string,
|
||||
ids: string[]
|
||||
) {
|
||||
const cursor = await collection(mongo).find({
|
||||
const cursor = collection(mongo).find({
|
||||
tenantID,
|
||||
id: {
|
||||
$in: ids,
|
||||
@@ -1098,7 +1099,7 @@ export async function updateUserEmail(
|
||||
return result.value;
|
||||
} catch (err) {
|
||||
if (err instanceof MongoError && err.code === 11000) {
|
||||
throw new DuplicateEmailError(email!);
|
||||
throw new DuplicateEmailError(email);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
@@ -1420,6 +1421,7 @@ export async function premodUser(
|
||||
|
||||
/**
|
||||
* removeUserPremod will lift a user premod requirement
|
||||
*
|
||||
* @param mongo the mongo database handle
|
||||
* @param tenantID the Tenant's ID where the User exists
|
||||
* @param id the ID of the user having their ban lifted
|
||||
@@ -2354,6 +2356,7 @@ export async function retrieveUserScheduledForDeletion(
|
||||
|
||||
/**
|
||||
* createModeratorNote will add a note to a users account
|
||||
*
|
||||
* @param mongo the database to put the notification digests into
|
||||
* @param tenantID the ID of the Tenant that this User exists on
|
||||
* @param id the ID of the User who is the subject of the note
|
||||
@@ -2397,6 +2400,7 @@ export async function createModeratorNote(
|
||||
|
||||
/**
|
||||
* deleteModeratorNote will remove a note from a user profile
|
||||
*
|
||||
* @param mongo the database to put the notification digests into
|
||||
* @param tenantID the ID of the Tenant that this User exists on
|
||||
* @param userID the ID of the user
|
||||
|
||||
@@ -256,8 +256,8 @@ export const createJobProcessor = (options: MailProcessorOptions) => {
|
||||
fromAddress,
|
||||
data
|
||||
);
|
||||
} catch (err) {
|
||||
throw new InternalError(err, "could not translate the message");
|
||||
} catch (e) {
|
||||
throw new InternalError(e, "could not translate the message");
|
||||
}
|
||||
|
||||
// Compute the end time.
|
||||
@@ -285,8 +285,8 @@ export const createJobProcessor = (options: MailProcessorOptions) => {
|
||||
|
||||
// Create the transport based on the smtp uri.
|
||||
transport = createTransport(opts);
|
||||
} catch (err) {
|
||||
throw new InternalError(err, "could not create email transport");
|
||||
} catch (e) {
|
||||
throw new InternalError(e, "could not create email transport");
|
||||
}
|
||||
|
||||
// Set the transport back into the cache.
|
||||
@@ -304,8 +304,8 @@ export const createJobProcessor = (options: MailProcessorOptions) => {
|
||||
try {
|
||||
// Send the mail message.
|
||||
await transport.sendMail(message);
|
||||
} catch (err) {
|
||||
throw new InternalError(err, "could not send email");
|
||||
} catch (e) {
|
||||
throw new InternalError(e, "could not send email");
|
||||
}
|
||||
|
||||
// Compute the end time.
|
||||
|
||||
@@ -16,11 +16,6 @@ import TenantCache from "coral-server/services/tenant/cache";
|
||||
|
||||
import { createJobProcessor, JOB_NAME, NotifierData } from "./processor";
|
||||
|
||||
export const createNotifierTask = (
|
||||
queue: Queue.QueueOptions,
|
||||
options: Options
|
||||
) => new NotifierQueue(queue, options);
|
||||
|
||||
interface Options {
|
||||
mongo: Db;
|
||||
mailerQueue: MailerQueue;
|
||||
@@ -69,3 +64,8 @@ export class NotifierQueue {
|
||||
return this.task.process();
|
||||
}
|
||||
}
|
||||
|
||||
export const createNotifierTask = (
|
||||
queue: Queue.QueueOptions,
|
||||
options: Options
|
||||
) => new NotifierQueue(queue, options);
|
||||
|
||||
@@ -161,7 +161,7 @@ export async function removeCommentAction(
|
||||
if (wasRemoved) {
|
||||
// Compute the action counts, and invert them (because we're deleting an
|
||||
// action).
|
||||
const actionCounts = invertEncodedActionCounts(encodeActionCounts(action!));
|
||||
const actionCounts = invertEncodedActionCounts(encodeActionCounts(action));
|
||||
|
||||
// Update the comment action counts here.
|
||||
const updatedComment = await updateCommentActionCounts(
|
||||
|
||||
@@ -258,23 +258,6 @@ export async function signString<T extends {}>(
|
||||
return jwt.sign(payload, secret, { ...options, algorithm });
|
||||
}
|
||||
|
||||
/**
|
||||
* extractJWTFromRequest will extract the token from the request if it can find
|
||||
* it. It first tries to get the token from the headers, then from the cookie.
|
||||
*
|
||||
* @param req the request to extract the JWT from
|
||||
* @param excludeQuery when true, does not pull from the query params
|
||||
*/
|
||||
export function extractTokenFromRequest(
|
||||
req: Request | IncomingMessage,
|
||||
excludeQuery: boolean = false
|
||||
): string | null {
|
||||
return (
|
||||
extractJWTFromRequestHeaders(req, excludeQuery) ||
|
||||
extractJWTFromRequestCookie(req)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* COOKIE_NAME is the name of the authorization cookie used by Coral.
|
||||
*/
|
||||
@@ -330,7 +313,7 @@ function extractJWTFromRequestCookie(
|
||||
*/
|
||||
function extractJWTFromRequestHeaders(
|
||||
req: Request | IncomingMessage,
|
||||
excludeQuery: boolean = false
|
||||
excludeQuery = false
|
||||
) {
|
||||
const options: BearerOptions = {
|
||||
basic: "password",
|
||||
@@ -345,6 +328,23 @@ function extractJWTFromRequestHeaders(
|
||||
return permit.check(req) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* extractJWTFromRequest will extract the token from the request if it can find
|
||||
* it. It first tries to get the token from the headers, then from the cookie.
|
||||
*
|
||||
* @param req the request to extract the JWT from
|
||||
* @param excludeQuery when true, does not pull from the query params
|
||||
*/
|
||||
export function extractTokenFromRequest(
|
||||
req: Request | IncomingMessage,
|
||||
excludeQuery = false
|
||||
): string | null {
|
||||
return (
|
||||
extractJWTFromRequestHeaders(req, excludeQuery) ||
|
||||
extractJWTFromRequestCookie(req)
|
||||
);
|
||||
}
|
||||
|
||||
function generateJTIRevokedKey(jti: string) {
|
||||
// jtir: JTI Revoked namespace.
|
||||
return `jtir:${jti}`;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// tslint:disable: max-classes-per-file
|
||||
/* eslint-disable max-classes-per-file */
|
||||
|
||||
import VError from "verror";
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import logger from "coral-server/logger";
|
||||
type IndexType = 1 | -1 | "text";
|
||||
|
||||
export type IndexSpecification<T> = {
|
||||
[P in keyof Writable<Partial<T>>]: IndexType
|
||||
[P in keyof Writable<Partial<T>>]: IndexType;
|
||||
} &
|
||||
Record<string, IndexType>;
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ export default class Manager {
|
||||
private clientID: string;
|
||||
private migrations: Migration[];
|
||||
private tenantCache: TenantCache;
|
||||
private ran: boolean = false;
|
||||
private ran = false;
|
||||
|
||||
constructor({ tenantCache, i18n }: ManagerOptions) {
|
||||
this.clientID = uuid.v4();
|
||||
@@ -58,10 +58,11 @@ export default class Manager {
|
||||
|
||||
// Load the migration.
|
||||
const filePath = path.join(__dirname, "migrations", fileName);
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const m = require(filePath);
|
||||
|
||||
// Parse the timestamp out of the migration filename.
|
||||
const matches = fileName.match(fileNamePattern);
|
||||
const matches = fileNamePattern.exec(fileName);
|
||||
if (!matches || matches.length !== 3) {
|
||||
throw new Error("fileName format is invalid");
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ export default class extends Migration {
|
||||
|
||||
public async test(mongo: Db, tenantID: string) {
|
||||
// Find all the users that still have premod status unset.
|
||||
const cursor = await collections
|
||||
const cursor = collections
|
||||
.users(mongo)
|
||||
.find({
|
||||
"status.premod": null,
|
||||
|
||||
@@ -37,10 +37,7 @@ function attachHandlers(redis: Redis) {
|
||||
});
|
||||
}
|
||||
|
||||
export function createRedisClient(
|
||||
config: Config,
|
||||
lazyConnect: boolean = false
|
||||
): Redis {
|
||||
export function createRedisClient(config: Config, lazyConnect = false): Redis {
|
||||
try {
|
||||
const options = config.get("redis_options") || {};
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ export async function remove(
|
||||
mongo: Db,
|
||||
tenant: Tenant,
|
||||
storyID: string,
|
||||
includeComments: boolean = false
|
||||
includeComments = false
|
||||
) {
|
||||
// Create a logger for this function.
|
||||
const log = logger.child(
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ export default class TenantCache {
|
||||
/**
|
||||
* primed is true when the cache has already been fully primed.
|
||||
*/
|
||||
private primed: boolean = false;
|
||||
private primed = false;
|
||||
|
||||
/**
|
||||
* Create a new client application ID. This prevents duplicated messages
|
||||
|
||||
@@ -73,6 +73,14 @@ export async function update(
|
||||
return updatedTenant;
|
||||
}
|
||||
|
||||
/**
|
||||
* isInstalled will return a promise that if true, indicates that a Tenant has
|
||||
* been installed.
|
||||
*/
|
||||
export async function isInstalled(cache: TenantCache) {
|
||||
return (await cache.count()) > 0;
|
||||
}
|
||||
|
||||
export type InstallTenant = CreateTenantInput;
|
||||
|
||||
export async function install(
|
||||
@@ -108,14 +116,6 @@ export async function canInstall(cache: TenantCache) {
|
||||
return (await cache.count()) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* isInstalled will return a promise that if true, indicates that a Tenant has
|
||||
* been installed.
|
||||
*/
|
||||
export async function isInstalled(cache: TenantCache) {
|
||||
return (await cache.count()) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* regenerateSSOKey will regenerate the Single Sign-On key for the specified
|
||||
* Tenant and notify all other Tenant's connected that the Tenant was updated.
|
||||
|
||||
@@ -25,7 +25,7 @@ export function isURLPermitted(
|
||||
export function isURLPermitted(
|
||||
tenant: Pick<Tenant, "allowedDomains" | "domain">,
|
||||
targetURL: string,
|
||||
includeTenantDomain: boolean = false
|
||||
includeTenantDomain = false
|
||||
) {
|
||||
// If there aren't any domains, then we reject it, because no url we have can
|
||||
// satisfy those requirements.
|
||||
|
||||
@@ -371,7 +371,7 @@ export async function requestAccountDeletion(
|
||||
|
||||
const updatedUser = await scheduleDeletionDate(
|
||||
mongo,
|
||||
tenant.id!,
|
||||
tenant.id,
|
||||
user.id,
|
||||
deletionDate.toJSDate()
|
||||
);
|
||||
@@ -619,6 +619,7 @@ export async function updateRole(
|
||||
|
||||
/**
|
||||
* enabledAuthenticationIntegrations returns enabled auth integrations for a tenant
|
||||
*
|
||||
* @param tenant Tenant where the User will be interacted with
|
||||
* @param target whether to filter by stream or admin enabled. defaults to requiring both.
|
||||
*/
|
||||
@@ -639,6 +640,7 @@ function enabledAuthenticationIntegrations(
|
||||
|
||||
/**
|
||||
* canUpdateLocalProfile will determine if a user is permitted to update their email address.
|
||||
*
|
||||
* @param tenant Tenant where the User will be interacted with
|
||||
* @param user the User that we are updating
|
||||
*/
|
||||
@@ -662,6 +664,7 @@ function canUpdateLocalProfile(tenant: Tenant, user: User): boolean {
|
||||
|
||||
/**
|
||||
* updateEmail will update the current User's email address.
|
||||
*
|
||||
* @param mongo mongo database to interact with
|
||||
* @param tenant Tenant where the User will be interacted with
|
||||
* @param mailer The mailer queue
|
||||
|
||||
Reference in New Issue
Block a user