feat: Add ctx.state.authType for tracking (#1567)
This commit is contained in:
@@ -2,14 +2,17 @@
|
|||||||
import addMinutes from "date-fns/add_minutes";
|
import addMinutes from "date-fns/add_minutes";
|
||||||
import addMonths from "date-fns/add_months";
|
import addMonths from "date-fns/add_months";
|
||||||
import JWT from "jsonwebtoken";
|
import JWT from "jsonwebtoken";
|
||||||
import { type Context } from "koa";
|
|
||||||
import { AuthenticationError, UserSuspendedError } from "../errors";
|
import { AuthenticationError, UserSuspendedError } from "../errors";
|
||||||
import { User, ApiKey } from "../models";
|
import { User, Team, ApiKey } from "../models";
|
||||||
|
import type { ContextWithState } from "../types";
|
||||||
import { getCookieDomain } from "../utils/domains";
|
import { getCookieDomain } from "../utils/domains";
|
||||||
import { getUserForJWT } from "../utils/jwt";
|
import { getUserForJWT } from "../utils/jwt";
|
||||||
|
|
||||||
export default function auth(options?: { required?: boolean } = {}) {
|
export default function auth(options?: { required?: boolean } = {}) {
|
||||||
return async function authMiddleware(ctx: Context, next: () => Promise<*>) {
|
return async function authMiddleware(
|
||||||
|
ctx: ContextWithState,
|
||||||
|
next: () => Promise<mixed>
|
||||||
|
) {
|
||||||
let token;
|
let token;
|
||||||
|
|
||||||
const authorizationHeader = ctx.request.get("authorization");
|
const authorizationHeader = ctx.request.get("authorization");
|
||||||
@@ -27,7 +30,6 @@ export default function auth(options?: { required?: boolean } = {}) {
|
|||||||
`Bad Authorization header format. Format is "Authorization: Bearer <token>"`
|
`Bad Authorization header format. Format is "Authorization: Bearer <token>"`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// $FlowFixMe
|
|
||||||
} else if (ctx.body && ctx.body.token) {
|
} else if (ctx.body && ctx.body.token) {
|
||||||
token = ctx.body.token;
|
token = ctx.body.token;
|
||||||
} else if (ctx.request.query.token) {
|
} else if (ctx.request.query.token) {
|
||||||
@@ -43,7 +45,8 @@ export default function auth(options?: { required?: boolean } = {}) {
|
|||||||
let user;
|
let user;
|
||||||
if (token) {
|
if (token) {
|
||||||
if (String(token).match(/^[\w]{38}$/)) {
|
if (String(token).match(/^[\w]{38}$/)) {
|
||||||
// API key
|
ctx.state.authType = "api";
|
||||||
|
|
||||||
let apiKey;
|
let apiKey;
|
||||||
try {
|
try {
|
||||||
apiKey = await ApiKey.findOne({
|
apiKey = await ApiKey.findOne({
|
||||||
@@ -51,18 +54,22 @@ export default function auth(options?: { required?: boolean } = {}) {
|
|||||||
secret: token,
|
secret: token,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
throw new AuthenticationError("Invalid API key");
|
throw new AuthenticationError("Invalid API key");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!apiKey) throw new AuthenticationError("Invalid API key");
|
if (!apiKey) {
|
||||||
|
throw new AuthenticationError("Invalid API key");
|
||||||
|
}
|
||||||
|
|
||||||
user = await User.findByPk(apiKey.userId);
|
user = await User.findByPk(apiKey.userId);
|
||||||
if (!user) throw new AuthenticationError("Invalid API key");
|
if (!user) {
|
||||||
|
throw new AuthenticationError("Invalid API key");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* $FlowFixMeNowPlease This comment suppresses an error found when upgrading
|
ctx.state.authType = "app";
|
||||||
* flow-bin@0.104.0. To view the error, delete this comment and run Flow. */
|
|
||||||
user = await getUserForJWT(token);
|
user = await getUserForJWT(String(token));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.isSuspended) {
|
if (user.isSuspended) {
|
||||||
@@ -76,21 +83,16 @@ export default function auth(options?: { required?: boolean } = {}) {
|
|||||||
// not awaiting the promise here so that the request is not blocked
|
// not awaiting the promise here so that the request is not blocked
|
||||||
user.updateActiveAt(ctx.request.ip);
|
user.updateActiveAt(ctx.request.ip);
|
||||||
|
|
||||||
/* $FlowFixMeNowPlease This comment suppresses an error found when upgrading
|
ctx.state.token = String(token);
|
||||||
* flow-bin@0.104.0. To view the error, delete this comment and run Flow. */
|
|
||||||
ctx.state.token = token;
|
|
||||||
|
|
||||||
/* $FlowFixMeNowPlease This comment suppresses an error found when upgrading
|
|
||||||
* flow-bin@0.104.0. To view the error, delete this comment and run Flow. */
|
|
||||||
ctx.state.user = user;
|
ctx.state.user = user;
|
||||||
if (!ctx.cache) ctx.cache = {};
|
|
||||||
|
|
||||||
/* $FlowFixMeNowPlease This comment suppresses an error found when upgrading
|
|
||||||
* flow-bin@0.104.0. To view the error, delete this comment and run Flow. */
|
|
||||||
ctx.cache[user.id] = user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.signIn = async (user, team, service, isFirstSignin = false) => {
|
ctx.signIn = async (
|
||||||
|
user: User,
|
||||||
|
team: Team,
|
||||||
|
service,
|
||||||
|
isFirstSignin = false
|
||||||
|
) => {
|
||||||
if (user.isSuspended) {
|
if (user.isSuspended) {
|
||||||
return ctx.redirect("/?notice=suspended");
|
return ctx.redirect("/?notice=suspended");
|
||||||
}
|
}
|
||||||
|
|||||||
12
server/types.js
Normal file
12
server/types.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// @flow
|
||||||
|
import { type Context } from "koa";
|
||||||
|
import { User } from "./models";
|
||||||
|
|
||||||
|
export type ContextWithState = {|
|
||||||
|
...$Exact<Context>,
|
||||||
|
state: {
|
||||||
|
user: User,
|
||||||
|
token: string,
|
||||||
|
authType: "app" | "api",
|
||||||
|
},
|
||||||
|
|};
|
||||||
@@ -18,7 +18,7 @@ function getJWTPayload(token) {
|
|||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getUserForJWT(token: string) {
|
export async function getUserForJWT(token: string): Promise<User> {
|
||||||
const payload = getJWTPayload(token);
|
const payload = getJWTPayload(token);
|
||||||
const user = await User.findByPk(payload.id);
|
const user = await User.findByPk(payload.id);
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ export async function getUserForJWT(token: string) {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getUserForEmailSigninToken(token: string) {
|
export async function getUserForEmailSigninToken(token: string): Promise<User> {
|
||||||
const payload = getJWTPayload(token);
|
const payload = getJWTPayload(token);
|
||||||
|
|
||||||
// check the token is within it's expiration time
|
// check the token is within it's expiration time
|
||||||
|
|||||||
Reference in New Issue
Block a user