diff --git a/schema.gql b/schema.gql index 2b4e7ff0..b1e75f36 100644 --- a/schema.gql +++ b/schema.gql @@ -133,7 +133,7 @@ input LoginInput { type Mutation { register(input: RegisterInput!): AuthModel! - totp: AuthModel! + totp: TOTPModel! createAnnouncement(input: CreateAnnouncementInput!): AnnouncementModel! updateAnnouncementById(input: UpdateAnnouncementInput!): AnnouncementModel! deleteAnnouncementById(id: ID!): AnnouncementModel! @@ -278,6 +278,10 @@ type SMSModel { updatedAt: DateTime! } +type TOTPModel { + qrcode: String! +} + input UpdateAgendaInput { id: String! title: String diff --git a/src/auth/auth.resolver.ts b/src/auth/auth.resolver.ts index 79273899..9432419f 100644 --- a/src/auth/auth.resolver.ts +++ b/src/auth/auth.resolver.ts @@ -1,6 +1,7 @@ import { Args, Query, Resolver, Mutation } from '@nestjs/graphql' import { AuthService } from './auth.service' import { AuthModel } from './models/auth.model' +import { TOTPModel } from './models/totp.model' import { LoginInput } from './dtos/login.input' import { RegisterInput } from './dtos/register.input' @@ -20,7 +21,7 @@ export class AuthResolver { return this.authService.register(input) } - @Mutation(() => AuthModel) + @Mutation(() => TOTPModel) public async totp() { return this.authService.totp() } diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index c73c1387..6ffd68ff 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common' import { ForbiddenError, AuthenticationError } from 'apollo-server-express' import { JwtService } from '@nestjs/jwt' import speakeasy from 'speakeasy' -import QRCode from 'qrcode' +import { generateQRCode } from '../shared/utils' import { UsersService } from '../users/users.service' import { Roles, User } from '../users/interfaces/user.interface' import { LoginInput } from './dtos/login.input' @@ -60,6 +60,6 @@ export class AuthService { public async totp() { const { base32, otpauth_url } = speakeasy.generateSecret() - QRCode.toDataURL(otpauth_url, (err, data_url) => ({ qrcode: data_url })) + return generateQRCode(otpauth_url) } } diff --git a/src/auth/models/totp.model.ts b/src/auth/models/totp.model.ts new file mode 100644 index 00000000..bd7e9cb9 --- /dev/null +++ b/src/auth/models/totp.model.ts @@ -0,0 +1,7 @@ +import { Field, ObjectType } from '@nestjs/graphql' + +@ObjectType() +export class TOTPModel { + @Field() + public readonly qrcode: string +} diff --git a/src/shared/utils.ts b/src/shared/utils.ts index 35f7e0b3..97b6f508 100644 --- a/src/shared/utils.ts +++ b/src/shared/utils.ts @@ -1,4 +1,16 @@ +import QRCode from 'qrcode' +import { ApolloError } from 'apollo-server-express' + export const generateSMSVerificationCode = () => (Math.floor(Math.random() * 10000) + 10000).toString().slice(1) export const jsonStringify = (obj: T) => JSON.stringify(obj).replace(/"([^(")"]+)":/g, '$1:') + +export const generateQRCode = async (url: string) => { + try { + const qrcode = await QRCode.toDataURL(url) + return { qrcode } + } catch (err) { + throw new ApolloError('Generate QR code failed!') + } +}