parent
477787785e
commit
586efd5581
File diff suppressed because it is too large
Load Diff
@ -1,59 +1,90 @@ |
||||
import faker from "faker"; |
||||
import { createConnection, getConnection } from "typeorm"; |
||||
import { callSchema } from "../../utils/callSchema"; |
||||
import { User } from "../User"; |
||||
|
||||
const usersQuery = ` |
||||
query { |
||||
users { |
||||
email |
||||
} |
||||
}` |
||||
|
||||
beforeEach(() => { |
||||
return createConnection({ |
||||
type: "sqlite", |
||||
database: ":memory:", |
||||
dropSchema: true, |
||||
|
||||
import faker = require("faker") |
||||
import { createConnection, getConnection } from "typeorm" |
||||
import { callSchema } from "../../utils/callSchema" |
||||
import * as jwt from "../../utils/jwt" |
||||
import { User } from "../User" |
||||
|
||||
beforeAll(async () => { |
||||
return await createConnection({ |
||||
type: "postgres", |
||||
host: "localhost", |
||||
port: 5432, |
||||
database: "testing", |
||||
username: "postgres", |
||||
password: "postgres", |
||||
// dropSchema: true,
|
||||
entities: [User], |
||||
synchronize: true, |
||||
logging: false |
||||
}); |
||||
}); |
||||
|
||||
afterEach(() => { |
||||
let conn = getConnection(); |
||||
return conn.close(); |
||||
}); |
||||
|
||||
describe("resolver of", () => { |
||||
describe("users query", () => { |
||||
it("should return an empty array when no users are created", async () => { |
||||
const response = await callSchema({ |
||||
source: usersQuery, |
||||
}) |
||||
|
||||
expect(response).toMatchObject({ |
||||
data: { |
||||
users: [], |
||||
}, |
||||
}) |
||||
logging: false, |
||||
}) |
||||
}) |
||||
|
||||
afterAll(async () => { |
||||
return await getConnection().close() |
||||
}) |
||||
|
||||
afterEach(async () => { |
||||
return await getConnection().synchronize(true) |
||||
}) |
||||
|
||||
describe("resolver of user", () => { |
||||
it("returns email as it creates user with mutation", async () => { |
||||
|
||||
const fakeEmail = faker.internet.email() |
||||
const fakePassword = faker.internet.password(6) |
||||
const createUserMutation = `mutation {
|
||||
createUser(email: "${fakeEmail}", password: "${fakePassword}") { |
||||
email |
||||
} |
||||
}` |
||||
|
||||
const response = await callSchema(createUserMutation) |
||||
|
||||
expect(response).toMatchObject({ |
||||
data: { |
||||
createUser: { email: fakeEmail }, |
||||
}, |
||||
}) |
||||
}) |
||||
|
||||
it("should return emails of registered users", async () => { |
||||
|
||||
it("should return a populated array when an user is created", async () => { |
||||
const user = await User.create({ |
||||
email: faker.internet.email(), |
||||
}).save() |
||||
const usersQuery = `{
|
||||
users { |
||||
email |
||||
} |
||||
}` |
||||
|
||||
const response = await callSchema({ |
||||
source: usersQuery, |
||||
}) |
||||
const user = await User.create({ |
||||
email: faker.internet.email(), |
||||
}).save() |
||||
|
||||
expect(response).toMatchObject({ |
||||
data: { |
||||
users: [{ email: user.email }], |
||||
}, |
||||
}) |
||||
const response = await callSchema(usersQuery) |
||||
|
||||
expect(response).toMatchObject({ |
||||
data: { |
||||
users: [{ email: user.email }], |
||||
}, |
||||
}) |
||||
}) |
||||
|
||||
it("should return a valid login token", async () => { |
||||
|
||||
const fakeEmail = faker.internet.email() |
||||
const fakePassword = faker.internet.password(6) |
||||
await User.create({ |
||||
email: fakeEmail, |
||||
password: fakePassword, |
||||
}).save() |
||||
|
||||
const loginTokenQuery = `{
|
||||
loginToken(email: "${fakeEmail}", password: "${fakePassword}")
|
||||
}` |
||||
|
||||
const response = await callSchema(loginTokenQuery) |
||||
const token = response.data!.loginToken; |
||||
|
||||
expect(jwt.verify(token, jwt.PUBLIC_KEY)).toBeTruthy() |
||||
}) |
||||
}) |
||||
|
@ -1,14 +1,45 @@ |
||||
import "reflect-metadata"; |
||||
import { Query, Resolver } from "type-graphql"; |
||||
import { getRepository } from "typeorm"; |
||||
import { User } from "../User"; |
||||
import "reflect-metadata" |
||||
import { Arg, Mutation, Query, Resolver } from "type-graphql" |
||||
import * as argon2 from "../../utils/argon2" |
||||
import * as jwt from "../../utils/jwt" |
||||
import { User } from "../User" |
||||
|
||||
@Resolver(_of => User) |
||||
@Resolver(() => User) |
||||
export class UserResolver { |
||||
|
||||
@Query(_returns => [User]) |
||||
@Query(() => [User]) |
||||
async users() { |
||||
const userRepository = getRepository(User) |
||||
return userRepository.find() |
||||
return await User.find() |
||||
} |
||||
|
||||
@Query(() => String, { nullable: true }) |
||||
async loginToken( |
||||
@Arg("email") email: string, |
||||
@Arg("password") password: string |
||||
): Promise<string | null> { |
||||
const user = await User.findOne({ where: { email } }) |
||||
|
||||
if (!user) { |
||||
return null |
||||
} |
||||
|
||||
const passwordValid = await argon2.verify(user.password, password) |
||||
|
||||
if (!passwordValid) { |
||||
return null |
||||
} |
||||
|
||||
const token = jwt.signWithRS256({ userId: user.id }) |
||||
return token |
||||
} |
||||
|
||||
@Mutation(() => User) |
||||
async createUser( |
||||
@Arg("email") email: string, |
||||
@Arg("password") password: string |
||||
): Promise<User> { |
||||
return await User.create({ |
||||
email, |
||||
password, |
||||
}).save() |
||||
} |
||||
} |
||||
|
@ -0,0 +1,10 @@ |
||||
import * as agron2 from "argon2" |
||||
export * from "argon2" |
||||
|
||||
/** |
||||
* Override the defaul agron2i option with agron2id |
||||
* @param password Pasword to has using argon2id |
||||
*/ |
||||
export async function hashIncludingOptions(password: string) { |
||||
return await agron2.hash(password, { type: agron2.argon2id }) |
||||
} |
@ -1,7 +1,16 @@ |
||||
import { buildSchema } from "type-graphql"; |
||||
import { UserResolver } from "../modules/User/UserResolver"; |
||||
import { buildSchema, MiddlewareFn } from "type-graphql" |
||||
import { UserResolver } from "../modules/User/UserResolver" |
||||
|
||||
const ErrorInterceptor: MiddlewareFn<any> = async ({}, next) => { |
||||
try { |
||||
return await next() |
||||
} catch (err) { |
||||
console.error(err) |
||||
} |
||||
} |
||||
|
||||
export const createSchema = () => |
||||
buildSchema({ |
||||
resolvers: [UserResolver], |
||||
globalMiddlewares: [ErrorInterceptor], |
||||
}) |
||||
|
@ -0,0 +1,12 @@ |
||||
import * as jwt from "jsonwebtoken" |
||||
export * from "jsonwebtoken" |
||||
|
||||
import fs = require('fs') |
||||
import path = require('path') |
||||
|
||||
const PRIVATE_KEY = fs.readFileSync(path.join(__dirname, 'keys', 'jwtRS256.key')) |
||||
export const PUBLIC_KEY = fs.readFileSync(path.join(__dirname, 'keys', 'jwtRS256.key.pub'))
|
||||
|
||||
export function signWithRS256(payload: string | object) { |
||||
return jwt.sign(payload, PRIVATE_KEY, {algorithm: "RS256"}) |
||||
} |
Loading…
Reference in new issue