UNPKG

@snowtop/ent-passport

Version:

snowtop ent passport integration

317 lines (316 loc) 10.6 kB
"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]); }); });