chore: Flag users with platform used
This commit is contained in:
@@ -123,7 +123,7 @@ export default function auth(options: AuthenticationOptions = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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).catch((err) => {
|
user.updateActiveAt(ctx).catch((err) => {
|
||||||
Logger.error("Failed to update user activeAt", err);
|
Logger.error("Failed to update user activeAt", err);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import {
|
|||||||
BeforeCreate,
|
BeforeCreate,
|
||||||
} from "sequelize-typescript";
|
} from "sequelize-typescript";
|
||||||
import { TeamValidation } from "@shared/validations";
|
import { TeamValidation } from "@shared/validations";
|
||||||
|
import env from "@server/env";
|
||||||
import { ValidationError } from "@server/errors";
|
import { ValidationError } from "@server/errors";
|
||||||
import isCloudHosted from "~/utils/isCloudHosted";
|
|
||||||
import Team from "./Team";
|
import Team from "./Team";
|
||||||
import User from "./User";
|
import User from "./User";
|
||||||
import IdModel from "./base/IdModel";
|
import IdModel from "./base/IdModel";
|
||||||
@@ -19,6 +19,8 @@ import Fix from "./decorators/Fix";
|
|||||||
import IsFQDN from "./validators/IsFQDN";
|
import IsFQDN from "./validators/IsFQDN";
|
||||||
import Length from "./validators/Length";
|
import Length from "./validators/Length";
|
||||||
|
|
||||||
|
const isCloudHosted = env.DEPLOYMENT === "hosted";
|
||||||
|
|
||||||
@Table({ tableName: "team_domains", modelName: "team_domain" })
|
@Table({ tableName: "team_domains", modelName: "team_domain" })
|
||||||
@Fix
|
@Fix
|
||||||
class TeamDomain extends IdModel {
|
class TeamDomain extends IdModel {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import { addMinutes, subMinutes } from "date-fns";
|
import { addMinutes, subMinutes } from "date-fns";
|
||||||
import JWT from "jsonwebtoken";
|
import JWT from "jsonwebtoken";
|
||||||
|
import { Context } from "koa";
|
||||||
import { Transaction, QueryTypes, SaveOptions, Op } from "sequelize";
|
import { Transaction, QueryTypes, SaveOptions, Op } from "sequelize";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
@@ -51,6 +52,8 @@ import NotContainsUrl from "./validators/NotContainsUrl";
|
|||||||
export enum UserFlag {
|
export enum UserFlag {
|
||||||
InviteSent = "inviteSent",
|
InviteSent = "inviteSent",
|
||||||
InviteReminderSent = "inviteReminderSent",
|
InviteReminderSent = "inviteReminderSent",
|
||||||
|
DesktopWeb = "desktopWeb",
|
||||||
|
MobileWeb = "mobileWeb",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum UserRole {
|
export enum UserRole {
|
||||||
@@ -264,8 +267,11 @@ class User extends ParanoidModel {
|
|||||||
if (!this.flags) {
|
if (!this.flags) {
|
||||||
this.flags = {};
|
this.flags = {};
|
||||||
}
|
}
|
||||||
this.flags[flag] = value ? 1 : 0;
|
const binary = value ? 1 : 0;
|
||||||
this.changed("flags", true);
|
if (this.flags[flag] !== binary) {
|
||||||
|
this.flags[flag] = binary;
|
||||||
|
this.changed("flags", true);
|
||||||
|
}
|
||||||
|
|
||||||
return this.flags;
|
return this.flags;
|
||||||
};
|
};
|
||||||
@@ -350,7 +356,8 @@ class User extends ParanoidModel {
|
|||||||
.map((c) => c.id);
|
.map((c) => c.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
updateActiveAt = async (ip: string, force = false) => {
|
updateActiveAt = async (ctx: Context, force = false) => {
|
||||||
|
const { ip } = ctx.request;
|
||||||
const fiveMinutesAgo = subMinutes(new Date(), 5);
|
const fiveMinutesAgo = subMinutes(new Date(), 5);
|
||||||
|
|
||||||
// ensure this is updated only every few minutes otherwise
|
// ensure this is updated only every few minutes otherwise
|
||||||
@@ -358,13 +365,20 @@ class User extends ParanoidModel {
|
|||||||
if (!this.lastActiveAt || this.lastActiveAt < fiveMinutesAgo || force) {
|
if (!this.lastActiveAt || this.lastActiveAt < fiveMinutesAgo || force) {
|
||||||
this.lastActiveAt = new Date();
|
this.lastActiveAt = new Date();
|
||||||
this.lastActiveIp = ip;
|
this.lastActiveIp = ip;
|
||||||
|
|
||||||
return this.save({
|
|
||||||
hooks: false,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
// Track the clients each user is using
|
||||||
|
if (ctx.userAgent.isMobile) {
|
||||||
|
this.setFlag(UserFlag.MobileWeb);
|
||||||
|
}
|
||||||
|
if (ctx.userAgent.isDesktop) {
|
||||||
|
this.setFlag(UserFlag.DesktopWeb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save only writes to the database if there are changes
|
||||||
|
return this.save({
|
||||||
|
hooks: false,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateSignedIn = (ip: string) => {
|
updateSignedIn = (ip: string) => {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ router.post("developer.create_test_users", dev(), auth(), async (ctx) => {
|
|||||||
|
|
||||||
// Convert from invites to active users by marking as active
|
// Convert from invites to active users by marking as active
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
response.users.map((user) => user.updateActiveAt(ctx.request.ip, true))
|
response.users.map((user) => user.updateActiveAt(ctx, true))
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Koa, { DefaultContext, DefaultState } from "koa";
|
import Koa, { BaseContext, DefaultContext, DefaultState } from "koa";
|
||||||
import bodyParser from "koa-body";
|
import bodyParser from "koa-body";
|
||||||
import Router from "koa-router";
|
import Router from "koa-router";
|
||||||
|
import userAgent, { UserAgentContext } from "koa-useragent";
|
||||||
import env from "@server/env";
|
import env from "@server/env";
|
||||||
import { NotFoundError } from "@server/errors";
|
import { NotFoundError } from "@server/errors";
|
||||||
import errorHandling from "@server/middlewares/errorHandling";
|
import errorHandling from "@server/middlewares/errorHandling";
|
||||||
@@ -50,6 +51,7 @@ api.use(
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
api.use<BaseContext, UserAgentContext>(userAgent);
|
||||||
api.use(methodOverride());
|
api.use(methodOverride());
|
||||||
api.use(apiWrapper());
|
api.use(apiWrapper());
|
||||||
api.use(editor());
|
api.use(editor());
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ router.get("/redirect", auth(), async (ctx) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ensure that the lastActiveAt on user is updated to prevent replay requests
|
// ensure that the lastActiveAt on user is updated to prevent replay requests
|
||||||
await user.updateActiveAt(ctx.request.ip, true);
|
await user.updateActiveAt(ctx, true);
|
||||||
|
|
||||||
ctx.cookies.set("accessToken", jwtToken, {
|
ctx.cookies.set("accessToken", jwtToken, {
|
||||||
httpOnly: false,
|
httpOnly: false,
|
||||||
expires: addMonths(new Date(), 3),
|
expires: addMonths(new Date(), 3),
|
||||||
|
|||||||
Reference in New Issue
Block a user