chore: Migrate authentication to new tables (#1929)
This work provides a foundation for a more pluggable authentication system such as the one outlined in #1317. closes #1317
This commit is contained in:
51
server/models/AuthenticationProvider.js
Normal file
51
server/models/AuthenticationProvider.js
Normal file
@@ -0,0 +1,51 @@
|
||||
// @flow
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { DataTypes, sequelize } from "../sequelize";
|
||||
|
||||
// Each authentication provider must have a definition under server/auth, the
|
||||
// name of the file will be used as reference in the db, one less thing to config
|
||||
const authProviders = fs
|
||||
.readdirSync(path.resolve(__dirname, "..", "auth"))
|
||||
.filter(
|
||||
(file) =>
|
||||
file.indexOf(".") !== 0 &&
|
||||
!file.includes(".test") &&
|
||||
!file.includes("index.js")
|
||||
)
|
||||
.map((fileName) => fileName.replace(".js", ""));
|
||||
|
||||
const AuthenticationProvider = sequelize.define(
|
||||
"authentication_providers",
|
||||
{
|
||||
id: {
|
||||
type: DataTypes.UUID,
|
||||
defaultValue: DataTypes.UUIDV4,
|
||||
primaryKey: true,
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
validate: {
|
||||
isIn: [authProviders],
|
||||
},
|
||||
},
|
||||
enabled: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: true,
|
||||
},
|
||||
providerId: {
|
||||
type: DataTypes.STRING,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
updatedAt: false,
|
||||
}
|
||||
);
|
||||
|
||||
AuthenticationProvider.associate = (models) => {
|
||||
AuthenticationProvider.belongsTo(models.Team);
|
||||
AuthenticationProvider.hasMany(models.UserAuthentication);
|
||||
};
|
||||
|
||||
export default AuthenticationProvider;
|
||||
@@ -249,9 +249,7 @@ describe("#membershipUserIds", () => {
|
||||
const users = await Promise.all(
|
||||
Array(6)
|
||||
.fill()
|
||||
.map(() => {
|
||||
return buildUser({ teamId });
|
||||
})
|
||||
.map(() => buildUser({ teamId }))
|
||||
);
|
||||
|
||||
const collection = await buildCollection({
|
||||
|
||||
@@ -96,6 +96,14 @@ Team.associate = (models) => {
|
||||
Team.hasMany(models.Collection, { as: "collections" });
|
||||
Team.hasMany(models.Document, { as: "documents" });
|
||||
Team.hasMany(models.User, { as: "users" });
|
||||
Team.hasMany(models.AuthenticationProvider, {
|
||||
as: "authenticationProviders",
|
||||
});
|
||||
Team.addScope("withAuthenticationProviders", {
|
||||
include: [
|
||||
{ model: models.AuthenticationProvider, as: "authenticationProviders" },
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
const uploadAvatar = async (model) => {
|
||||
@@ -121,13 +129,13 @@ const uploadAvatar = async (model) => {
|
||||
}
|
||||
};
|
||||
|
||||
Team.prototype.provisionSubdomain = async function (subdomain) {
|
||||
Team.prototype.provisionSubdomain = async function (subdomain, options = {}) {
|
||||
if (this.subdomain) return this.subdomain;
|
||||
|
||||
let append = 0;
|
||||
while (true) {
|
||||
try {
|
||||
await this.update({ subdomain });
|
||||
await this.update({ subdomain }, options);
|
||||
break;
|
||||
} catch (err) {
|
||||
// subdomain was invalid or already used, try again
|
||||
|
||||
@@ -79,7 +79,12 @@ User.associate = (models) => {
|
||||
});
|
||||
User.hasMany(models.Document, { as: "documents" });
|
||||
User.hasMany(models.View, { as: "views" });
|
||||
User.hasMany(models.UserAuthentication, { as: "authentications" });
|
||||
User.belongsTo(models.Team);
|
||||
|
||||
User.addScope("withAuthentications", {
|
||||
include: [{ model: models.UserAuthentication, as: "authentications" }],
|
||||
});
|
||||
};
|
||||
|
||||
// Instance methods
|
||||
@@ -151,10 +156,6 @@ User.prototype.getTransferToken = function () {
|
||||
// Returns a temporary token that is only used for logging in from an email
|
||||
// It can only be used to sign in once and has a medium length expiry
|
||||
User.prototype.getEmailSigninToken = function () {
|
||||
if (this.service && this.service !== "email") {
|
||||
throw new Error("Cannot generate email signin token for OAuth user");
|
||||
}
|
||||
|
||||
return JWT.sign(
|
||||
{ id: this.id, createdAt: new Date().toISOString(), type: "email-signin" },
|
||||
this.jwtSecret
|
||||
|
||||
24
server/models/UserAuthentication.js
Normal file
24
server/models/UserAuthentication.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// @flow
|
||||
import { DataTypes, sequelize, encryptedFields } from "../sequelize";
|
||||
|
||||
const UserAuthentication = sequelize.define("user_authentications", {
|
||||
id: {
|
||||
type: DataTypes.UUID,
|
||||
defaultValue: DataTypes.UUIDV4,
|
||||
primaryKey: true,
|
||||
},
|
||||
scopes: DataTypes.ARRAY(DataTypes.STRING),
|
||||
accessToken: encryptedFields().vault("accessToken"),
|
||||
refreshToken: encryptedFields().vault("refreshToken"),
|
||||
providerId: {
|
||||
type: DataTypes.STRING,
|
||||
unique: true,
|
||||
},
|
||||
});
|
||||
|
||||
UserAuthentication.associate = (models) => {
|
||||
UserAuthentication.belongsTo(models.AuthenticationProvider);
|
||||
UserAuthentication.belongsTo(models.User);
|
||||
};
|
||||
|
||||
export default UserAuthentication;
|
||||
@@ -2,6 +2,7 @@
|
||||
import ApiKey from "./ApiKey";
|
||||
import Attachment from "./Attachment";
|
||||
import Authentication from "./Authentication";
|
||||
import AuthenticationProvider from "./AuthenticationProvider";
|
||||
import Backlink from "./Backlink";
|
||||
import Collection from "./Collection";
|
||||
import CollectionGroup from "./CollectionGroup";
|
||||
@@ -19,12 +20,14 @@ import Share from "./Share";
|
||||
import Star from "./Star";
|
||||
import Team from "./Team";
|
||||
import User from "./User";
|
||||
import UserAuthentication from "./UserAuthentication";
|
||||
import View from "./View";
|
||||
|
||||
const models = {
|
||||
ApiKey,
|
||||
Attachment,
|
||||
Authentication,
|
||||
AuthenticationProvider,
|
||||
Backlink,
|
||||
Collection,
|
||||
CollectionGroup,
|
||||
@@ -42,6 +45,7 @@ const models = {
|
||||
Star,
|
||||
Team,
|
||||
User,
|
||||
UserAuthentication,
|
||||
View,
|
||||
};
|
||||
|
||||
@@ -56,6 +60,7 @@ export {
|
||||
ApiKey,
|
||||
Attachment,
|
||||
Authentication,
|
||||
AuthenticationProvider,
|
||||
Backlink,
|
||||
Collection,
|
||||
CollectionGroup,
|
||||
@@ -73,5 +78,6 @@ export {
|
||||
Star,
|
||||
Team,
|
||||
User,
|
||||
UserAuthentication,
|
||||
View,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user