@snowtop/ent-passport
Version:
snowtop ent passport integration
317 lines (316 loc) • 10.6 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const ent_1 = require("@snowtop/ent");
const ent_graphql_tests_1 = require("@snowtop/ent-graphql-tests");
const auth_1 = require("@snowtop/ent/auth");
const temp_db_1 = require("@snowtop/ent/testutils/db/temp_db");
const graphql_1 = require("graphql");
const write_1 = require("@snowtop/ent/testutils/write");
const passport_1 = require("./passport");
const passport_2 = require("./passport");
const supertest_1 = __importDefault(require("supertest"));
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
const db_1 = require("@snowtop/ent/core/db");
const builder_1 = require("@snowtop/ent/testutils/builder");
let tdb;
beforeAll(async () => {
tdb = new temp_db_1.TempDB(db_1.Dialect.Postgres, [
(0, temp_db_1.table)("users", (0, temp_db_1.text)("id", { primaryKey: true }), (0, temp_db_1.text)("first_name"), (0, temp_db_1.text)("last_name"), (0, temp_db_1.text)("email_address"), (0, temp_db_1.text)("password")),
]);
await tdb.beforeAll();
});
afterAll(async () => {
await tdb.afterAll();
});
afterEach(async () => {
(0, auth_1.clearAuthHandlers)();
await ent_1.DB.getInstance().getPool().exec("DELETE FROM users");
});
let userType = new graphql_1.GraphQLObjectType({
name: "User",
fields: {
id: {
type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLID),
},
firstName: {
type: graphql_1.GraphQLString,
},
lastName: {
type: graphql_1.GraphQLString,
},
emailAddress: {
type: graphql_1.GraphQLString,
},
},
});
class UserClass extends builder_1.BaseEnt {
constructor(viewer, options) {
super(viewer, options);
this.viewer = viewer;
this.nodeType = "User";
this.firstName = options.first_name;
this.lastName = options.last_name;
this.emailAddress = options.email_address;
}
static loaderOptions() {
const tableName = "users";
const fields = [
"id",
"first_name",
"last_name",
"email_address",
"password",
];
return {
ent: UserClass,
tableName,
fields,
loaderFactory: new ent_1.ObjectLoaderFactory({
tableName,
fields,
key: "id",
}),
};
}
}
let viewerType = new graphql_1.GraphQLObjectType({
name: "Viewer",
fields: {
user: {
type: userType,
async resolve(_source, args, context) {
const v = context.getViewer();
return await v.viewer();
},
},
},
});
let authUserPayloadType = new graphql_1.GraphQLObjectType({
name: "AuthUserPayload",
fields: {
token: {
type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString),
},
viewer: {
type: new graphql_1.GraphQLNonNull(viewerType),
},
},
});
const authUserType = {
args: {
emailAddress: {
type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString),
},
password: {
type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString),
},
},
type: new graphql_1.GraphQLNonNull(authUserPayloadType),
async resolve(_source, args, context) {
const [viewer, token] = await (0, passport_1.useAndVerifyAuthJWT)(context, async () => {
const row = await (0, ent_1.loadRow)({
tableName: "users",
clause: ent_1.query.And(ent_1.query.Eq("email_address", args["emailAddress"]), ent_1.query.Eq("password", args["password"])),
fields: ["id"],
});
return row === null || row === void 0 ? void 0 : row.id;
}, {
secretOrKey: "secret",
}, UserClass.loaderOptions(), {
session: false,
});
return {
viewer,
token,
};
},
};
const authUserSessionType = {
args: {
emailAddress: {
type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString),
},
password: {
type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString),
},
},
type: new graphql_1.GraphQLNonNull(viewerType),
async resolve(_source, args, context) {
return await (0, passport_1.useAndVerifyAuth)(context, async () => {
const row = await (0, ent_1.loadRow)({
tableName: "users",
clause: ent_1.query.And(ent_1.query.Eq("email_address", args["emailAddress"]), ent_1.query.Eq("password", args["password"])),
fields: ["id"],
});
return row === null || row === void 0 ? void 0 : row.id;
}, UserClass.loaderOptions());
},
};
const viewerType2 = {
args: {},
type: viewerType,
resolve(_source, args, context) {
return context.getViewer();
},
};
const mutationType = new graphql_1.GraphQLObjectType({
name: "MutationType",
fields: {
authUser: authUserType,
authUserSession: authUserSessionType,
},
});
const queryType = new graphql_1.GraphQLObjectType({
name: "QueryType",
fields: {
viewer: viewerType2,
},
});
const schema = new graphql_1.GraphQLSchema({
query: queryType,
mutation: mutationType,
});
test("logged out", async () => {
await (0, ent_graphql_tests_1.expectQueryFromRoot)({
root: "viewer",
args: {},
schema: schema,
nullQueryPaths: ["user"],
}, ["user.id", null]);
});
async function createUser(opts) {
return await (0, write_1.createRowForTest)({
tableName: "users",
fields: {
id: "1",
first_name: "Dany",
last_name: "Targaryen",
email_address: "dany@targaryen.com",
password: "12345678",
...opts,
},
}, "RETURNING *");
}
describe("jwt", () => {
test("logged in", async () => {
const user = await createUser();
let jwtToken = "";
const st = await (0, ent_graphql_tests_1.expectMutation)({
mutation: "authUser",
schema,
disableInputWrapping: true,
args: {
emailAddress: "dany@targaryen.com",
password: "12345678",
},
init: passport_2.PassportStrategyHandler.testInitJWTFunction({
secretOrKey: "secret",
loaderOptions: UserClass.loaderOptions(),
}),
}, ["viewer.user.id", "1"], [
"token",
function (token) {
const decoded = jsonwebtoken_1.default.decode(token);
expect(decoded).not.toBe(null);
expect(decoded["viewerID"]).toBe(user === null || user === void 0 ? void 0 : user.id);
jwtToken = token;
},
]);
let headers = {};
if (jwtToken) {
headers["Authorization"] = `Bearer ${jwtToken}`;
}
// user is logged in
await (0, ent_graphql_tests_1.expectQueryFromRoot)({
root: "viewer",
schema,
args: {},
test: st,
headers: headers,
}, ["user.id", "1"], ["user.emailAddress", "dany@targaryen.com"]);
// user still logged in without st since this is session-less
await (0, ent_graphql_tests_1.expectQueryFromRoot)({
root: "viewer",
schema,
args: {},
headers: headers,
}, ["user.id", "1"]);
// no headers, user logged out
await (0, ent_graphql_tests_1.expectQueryFromRoot)({
root: "viewer",
schema,
test: st,
args: {},
nullQueryPaths: ["user"],
}, ["user.id", null]);
});
test("invalid credentials", async () => {
await (0, ent_graphql_tests_1.expectMutation)({
mutation: "authUser",
schema,
disableInputWrapping: true,
args: {
emailAddress: "dany@targaryen.com",
password: "12345678",
},
init: passport_2.PassportStrategyHandler.testInitJWTFunction({
secretOrKey: "secret",
loaderOptions: UserClass.loaderOptions(),
}),
expectedError: "invalid login credentials",
}, ["viewer.user.id", "1"]);
});
});
describe("session based", () => {
test("logged in", async () => {
await createUser();
const st = await (0, ent_graphql_tests_1.expectMutation)({
// pass a function that takes a server that keeps track of cookies etc
// and use that for this request
test: (app) => {
return supertest_1.default.agent(app);
},
mutation: "authUserSession",
schema,
disableInputWrapping: true,
args: {
emailAddress: "dany@targaryen.com",
password: "12345678",
},
init: passport_2.PassportAuthHandler.testInitSessionBasedFunction("secret", {
loadOptions: UserClass.loaderOptions(),
}),
}, ["user.id", "1"]);
// resend with authed server
// user is still logged in
await (0, ent_graphql_tests_1.expectQueryFromRoot)({
root: "viewer",
schema,
args: {},
test: st,
}, ["user.id", "1"], ["user.emailAddress", "dany@targaryen.com"]);
// user logged out if not attached to server
await (0, ent_graphql_tests_1.expectQueryFromRoot)({
root: "viewer",
schema,
args: {},
nullQueryPaths: ["user"],
}, ["user.id", null]);
});
test("invalid credentials", async () => {
await (0, ent_graphql_tests_1.expectMutation)({
mutation: "authUser",
schema,
disableInputWrapping: true,
args: {
emailAddress: "dany@targaryen.com",
password: "12345678",
},
init: passport_2.PassportAuthHandler.testInitSessionBasedFunction("secret"),
expectedError: "invalid login credentials",
}, ["viewer.user.id", null]);
});
});