refactor: refactored a few types around users and passwordless tokens in auth module
This commit is contained in:
@@ -10,10 +10,7 @@ import * as bcrypt from 'bcrypt';
|
||||
import * as O from 'fp-ts/Option';
|
||||
import * as E from 'fp-ts/Either';
|
||||
import * as TE from 'fp-ts/TaskEither';
|
||||
import {
|
||||
DeviceIdentifierToken,
|
||||
PasswordlessToken,
|
||||
} from 'src/types/Passwordless';
|
||||
import { DeviceIdentifierToken } from 'src/types/Passwordless';
|
||||
import {
|
||||
INVALID_EMAIL,
|
||||
INVALID_MAGIC_LINK_DATA,
|
||||
@@ -28,11 +25,11 @@ import {
|
||||
AuthTokens,
|
||||
RefreshTokenPayload,
|
||||
} from 'src/types/AuthTokens';
|
||||
import { ProviderAccount } from 'src/types/ProviderAccount';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { AuthErrorHandler } from 'src/types/AuthErrorHandler';
|
||||
import { AuthUser } from 'src/types/AuthUser';
|
||||
import { isLeafType } from 'graphql';
|
||||
import { PasswordlessVerification } from '@prisma/client';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
@@ -44,25 +41,24 @@ export class AuthService {
|
||||
) {}
|
||||
|
||||
// generate Id and token for email magiclink
|
||||
private async generatePasswordlessTokens(user: User) {
|
||||
private async generatePasswordlessTokens(user: AuthUser) {
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
const expiresOn = DateTime.now().plus({ hours: 3 }).toISO().toString();
|
||||
|
||||
const idToken: PasswordlessToken =
|
||||
await this.prismaService.passwordlessVerification.create({
|
||||
data: {
|
||||
deviceIdentifier: salt,
|
||||
userUid: user.id,
|
||||
expiresOn: expiresOn,
|
||||
},
|
||||
});
|
||||
const idToken = await this.prismaService.passwordlessVerification.create({
|
||||
data: {
|
||||
deviceIdentifier: salt,
|
||||
userUid: user.id,
|
||||
expiresOn: expiresOn,
|
||||
},
|
||||
});
|
||||
|
||||
return idToken;
|
||||
}
|
||||
|
||||
private async validatePasswordlessTokens(data: verifyMagicDto) {
|
||||
try {
|
||||
const tokens: PasswordlessToken =
|
||||
const tokens =
|
||||
await this.prismaService.passwordlessVerification.findUniqueOrThrow({
|
||||
where: {
|
||||
passwordless_deviceIdentifier_tokens: {
|
||||
@@ -79,7 +75,7 @@ export class AuthService {
|
||||
|
||||
private async UpdateUserRefreshToken(tokenHash: string, userUid: string) {
|
||||
try {
|
||||
const user: User = await this.prismaService.user.update({
|
||||
const user = await this.prismaService.user.update({
|
||||
where: {
|
||||
id: userUid,
|
||||
},
|
||||
@@ -143,7 +139,7 @@ export class AuthService {
|
||||
}
|
||||
|
||||
private async deletePasswordlessVerificationToken(
|
||||
passwordlessTokens: PasswordlessToken,
|
||||
passwordlessTokens: PasswordlessVerification,
|
||||
) {
|
||||
try {
|
||||
const deletedPasswordlessToken =
|
||||
@@ -162,15 +158,14 @@ export class AuthService {
|
||||
}
|
||||
|
||||
async checkIfProviderAccountExists(user: User, profile) {
|
||||
const provider: ProviderAccount =
|
||||
await this.prismaService.account.findUnique({
|
||||
where: {
|
||||
verifyProviderAccount: {
|
||||
provider: profile.provider,
|
||||
providerAccountId: profile.id,
|
||||
},
|
||||
const provider = await this.prismaService.account.findUnique({
|
||||
where: {
|
||||
verifyProviderAccount: {
|
||||
provider: profile.provider,
|
||||
providerAccountId: profile.id,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
if (!provider) return O.none;
|
||||
|
||||
@@ -186,7 +181,7 @@ export class AuthService {
|
||||
statusCode: HttpStatus.BAD_REQUEST,
|
||||
});
|
||||
|
||||
let user: User;
|
||||
let user: AuthUser;
|
||||
const queriedUser = await this.usersService.findUserByEmail(email);
|
||||
|
||||
if (O.isNone(queriedUser)) {
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
export interface AuthUser {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
image: string;
|
||||
isAdmin: boolean;
|
||||
refreshToken: string;
|
||||
createdOn: Date;
|
||||
}
|
||||
import { User } from '@prisma/client';
|
||||
|
||||
export type AuthUser = User;
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
import { User } from 'src/user/user.model';
|
||||
|
||||
export interface PasswordlessToken {
|
||||
deviceIdentifier: string;
|
||||
token: string;
|
||||
userUid: string;
|
||||
user?: User;
|
||||
expiresOn: Date;
|
||||
}
|
||||
|
||||
export interface DeviceIdentifierToken {
|
||||
deviceIdentifier: string;
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import { User } from 'src/user/user.model';
|
||||
|
||||
export interface ProviderAccount {
|
||||
id: string;
|
||||
userId: string;
|
||||
user?: User;
|
||||
provider: string;
|
||||
providerAccountId: string;
|
||||
providerRefreshToken?: string;
|
||||
providerAccessToken?: string;
|
||||
providerScope?: string;
|
||||
loggedIn: Date;
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import * as O from 'fp-ts/Option';
|
||||
import { User } from './user.model';
|
||||
import { ProviderAccount } from '../types/ProviderAccount';
|
||||
import { AuthUser } from 'src/types/AuthUser';
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
@@ -11,7 +8,7 @@ export class UserService {
|
||||
|
||||
async findUserByEmail(email: string) {
|
||||
try {
|
||||
const user: AuthUser = await this.prisma.user.findUniqueOrThrow({
|
||||
const user = await this.prisma.user.findUniqueOrThrow({
|
||||
where: {
|
||||
email: email,
|
||||
},
|
||||
@@ -24,7 +21,7 @@ export class UserService {
|
||||
|
||||
async findUserById(userUid: string) {
|
||||
try {
|
||||
const user: AuthUser = await this.prisma.user.findUniqueOrThrow({
|
||||
const user = await this.prisma.user.findUniqueOrThrow({
|
||||
where: {
|
||||
id: userUid,
|
||||
},
|
||||
@@ -36,7 +33,7 @@ export class UserService {
|
||||
}
|
||||
|
||||
async createUserMagic(email: string) {
|
||||
const createdUser: AuthUser = await this.prisma.user.create({
|
||||
const createdUser = await this.prisma.user.create({
|
||||
data: {
|
||||
email: email,
|
||||
accounts: {
|
||||
@@ -52,7 +49,7 @@ export class UserService {
|
||||
}
|
||||
|
||||
async createUserSSO(accessToken, refreshToken, profile) {
|
||||
const createdUser: AuthUser = await this.prisma.user.create({
|
||||
const createdUser = await this.prisma.user.create({
|
||||
data: {
|
||||
name: profile.displayName,
|
||||
email: profile.emails[0].value,
|
||||
@@ -72,7 +69,7 @@ export class UserService {
|
||||
}
|
||||
|
||||
async createProviderAccount(user, accessToken, refreshToken, profile) {
|
||||
const createdProvider: ProviderAccount = await this.prisma.account.create({
|
||||
const createdProvider = await this.prisma.account.create({
|
||||
data: {
|
||||
userId: user.id,
|
||||
provider: profile.provider,
|
||||
|
||||
172
packages/hoppscotch-backend/typescript
Normal file
172
packages/hoppscotch-backend/typescript
Normal file
@@ -0,0 +1,172 @@
|
||||
Script started on 2023-01-12 21:07:39+05:30 [TERM="xterm-256color" TTY="/dev/pts/3" COLUMNS="120" LINES="30"]
|
||||
[oh-my-zsh] Insecure completion-dependent directories detected:
|
||||
drwxrwxrwx 12 balubabu balubabu 4096 Jan 2 12:38 /home/balubabu/.oh-my-zsh
|
||||
drwxrwxrwx 3 balubabu balubabu 4096 Jan 2 12:38 /home/balubabu/.oh-my-zsh/cache
|
||||
drwxrwxrwx 2 balubabu balubabu 4096 Jan 2 12:38 /home/balubabu/.oh-my-zsh/cache/completions
|
||||
drwxrwxrwx 316 balubabu balubabu 12288 Jan 2 12:38 /home/balubabu/.oh-my-zsh/plugins
|
||||
drwxrwxrwx 2 balubabu balubabu 4096 Jan 2 12:38 /home/balubabu/.oh-my-zsh/plugins/git
|
||||
|
||||
[oh-my-zsh] For safety, we will not load completions from these directories until
|
||||
[oh-my-zsh] you fix their permissions and ownership and restart zsh.
|
||||
[oh-my-zsh] See the above list for directories with group or other writability.
|
||||
|
||||
[oh-my-zsh] To fix your permissions you can do so by disabling
|
||||
[oh-my-zsh] the write permission of "group" and "others" and making sure that the
|
||||
[oh-my-zsh] owner of these directories is either root or your current user.
|
||||
[oh-my-zsh] The following command may help:
|
||||
[oh-my-zsh] compaudit | xargs chmod g-w,o-w
|
||||
|
||||
[oh-my-zsh] If the above didn't help or you want to skip the verification of
|
||||
[oh-my-zsh] insecure directories you can set the variable ZSH_DISABLE_COMPFIX to
|
||||
[oh-my-zsh] "true" before oh-my-zsh is sourced in your zshrc file.
|
||||
|
||||
[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~/work/self-hosted/packages/hoppscotch-backend]1;..cotch-backend
|
||||
[0m[27m[24m[J[01;32m➜ [36mhoppscotch-backend[00m [01;34mgit:([31mfeat/user-authentication[34m) [33m✗[00m [K[?1h=[?2004hccls[?1l>[?2004l
|
||||
|
||||
]2;clear]1;cls[H[2J[3J[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~/work/self-hosted/packages/hoppscotch-backend]1;..cotch-backend
|
||||
[0m[27m[24m[J[01;32m➜ [36mhoppscotch-backend[00m [01;34mgit:([31mfeat/user-authentication[34m) [33m✗[00m [K[?1h=[?2004hmmigrate cd[?1l>[?2004l
|
||||
|
||||
]2;migrate cd]1;migratezsh: command not found: migrate
|
||||
[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~/work/self-hosted/packages/hoppscotch-backend]1;..cotch-backend
|
||||
[0m[27m[24m[J[01;31m➜ [36mhoppscotch-backend[00m [01;34mgit:([31mfeat/user-authentication[34m) [33m✗[00m [K[?1h=[?2004hbbash migrate[?1l>[?2004l
|
||||
|
||||
]2;bash migrate]1;bashbash: migrate: No such file or directory
|
||||
[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~/work/self-hosted/packages/hoppscotch-backend]1;..cotch-backend
|
||||
[0m[27m[24m[J[01;31m➜ [36mhoppscotch-backend[00m [01;34mgit:([31mfeat/user-authentication[34m) [33m✗[00m [K[?1h=[?2004hbash migrate.sh[?1l>[?2004l
|
||||
|
||||
]2;bash migrate.sh]1;bashbash: migrate.sh: No such file or directory
|
||||
[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~/work/self-hosted/packages/hoppscotch-backend]1;..cotch-backend
|
||||
[0m[27m[24m[J[01;31m➜ [36mhoppscotch-backend[00m [01;34mgit:([31mfeat/user-authentication[34m) [33m✗[00m [K[?1h=[?2004hccls[?1l>[?2004l
|
||||
|
||||
]2;clear]1;cls[H[2J[3J[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~/work/self-hosted/packages/hoppscotch-backend]1;..cotch-backend
|
||||
[0m[27m[24m[J[01;32m➜ [36mhoppscotch-backend[00m [01;34mgit:([31mfeat/user-authentication[34m) [33m✗[00m [K[?1h=[?2004hccd ~[?1l>[?2004l
|
||||
|
||||
]2;cd ~]1;cd[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~]1;~
|
||||
[0m[27m[24m[J[01;32m➜ [36m~[00m [K[?1h=[?2004h[7mchmod +x site-check.sh[27m[22D[27mc[27mh[27mm[27mo[27md[27m [27m+[27mx[27m [27ms[27mi[27mt[27me[27m-[27mc[27mh[27me[27mc[27mk[27m.[27ms[27mh.sh .sh .sh .sh .sh .sh .sh .sh .sh .sh m.shi.shg.shr.sha.sht.she.sh[?1l>[?2004l
|
||||
|
||||
]2;chmod +x migrate.sh]1;chmod[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~]1;~
|
||||
[0m[27m[24m[J[01;32m➜ [36m~[00m [K[?1h=[?2004hmmirM[2C
|
||||
|
||||
[J[0mMiracastInputMgr.dll [JMiracastReceiver.dll [JMiracastReceiverExt.dll [JMirrorDrvCompat.dll [J[A[0m[27m[24m
|
||||
[5CMir[Kir r mmigrate gdfchs[?1l>[?2004l
|
||||
|
||||
[J]2;migrate gdfchs]1;migratezsh: command not found: migrate
|
||||
[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~]1;~
|
||||
[0m[27m[24m[J[01;31m➜ [36m~[00m [K[?1h=[?2004h[7msudo cp site-check.sh /usr/bin/site-check[27m[41D[27ms[27mu[27md[27mo[27m [27mc[27mp[27m [27ms[27mi[27mt[27me[27m-[27mc[27mh[27me[27mc[27mk[27m.[27ms[27mh[27m [27m/[27mu[27ms[27mr[27m/[27mb[27mi[27mn[27m/[27ms[27mi[27mt[27me[27m-[27mc[27mh[27me[27mc[27mk migrate[P[20C [21D[P[20C [21D[P[20C [21D[P[20C [21D[P[20C [21D[P[20C [21D[P[20C [21D[P[20C [21D[P[20C [21D[P[20C [21Dm.sh /usr/bin/migrate[20Di.sh /usr/bin/migrate[20Dg.sh /usr/bin/migrate[20Dr.sh /usr/bin/migrate[20Da.sh /usr/bin/migrate[20Dt.sh /usr/bin/migrate[20De.sh /usr/bin/migrate[20D[?1l>[?2004l
|
||||
|
||||
]2;sudo cp migrate.sh /usr/bin/migrate]1;cp[sudo] password for balubabu:
|
||||
[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~]1;~
|
||||
[0m[27m[24m[J[01;32m➜ [36m~[00m [K[?1h=[?2004hmmir grate[?1l>[?2004l
|
||||
|
||||
]2;migrate]1;migrate"docker exec" requires at least 2 arguments.
|
||||
See 'docker exec --help'.
|
||||
|
||||
Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
|
||||
|
||||
Run a command in a running container
|
||||
[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~]1;~
|
||||
[0m[27m[24m[J[01;31m➜ [36m~[00m [K[?1h=[?2004hccls[?1l>[?2004l
|
||||
|
||||
]2;clear]1;cls[H[2J[3J[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~]1;~
|
||||
[0m[27m[24m[J[01;32m➜ [36m~[00m [K[?1h=[?2004hccd work[1m/[0m[0m/self-hosted[1m/[0m[0m/h packages[1m/[0m[0m/hoppscotch-backend[1m/[0m[0m [?1l>[?2004l
|
||||
|
||||
]2;cd work/self-hosted/packages/hoppscotch-backend]1;cd[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~/work/self-hosted/packages/hoppscotch-backend]1;..cotch-backend
|
||||
[0m[27m[24m[J[01;32m➜ [36mhoppscotch-backend[00m [01;34mgit:([31mfeat/user-authentication[34m) [33m✗[00m [K[?1h=[?2004hcc;s[?1l>[?2004l
|
||||
|
||||
]2;c; s]1;c;szsh: command not found: c
|
||||
zsh: command not found: s
|
||||
[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~/work/self-hosted/packages/hoppscotch-backend]1;..cotch-backend
|
||||
[0m[27m[24m[J[01;31m➜ [36mhoppscotch-backend[00m [01;34mgit:([31mfeat/user-authentication[34m) [33m✗[00m [K[?1h=[?2004hccls[?1l>[?2004l
|
||||
|
||||
]2;clear]1;cls[H[2J[3J[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~/work/self-hosted/packages/hoppscotch-backend]1;..cotch-backend
|
||||
[0m[27m[24m[J[01;32m➜ [36mhoppscotch-backend[00m [01;34mgit:([31mfeat/user-authentication[34m) [33m✗[00m [K[?1h=[?2004hddocker ps[?1l>[?2004l
|
||||
|
||||
]2;docker ps]1;dockerCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
f48d44a76ccc hoppscotch-backend-local "docker-entrypoint.s…" 50 minutes ago Up 50 minutes 3170/tcp, 0.0.0.0:9229->9229/tcp, 0.0.0.0:3170->3000/tcp hoppscotch-backend-local-1
|
||||
ca1f2c39cdb5 postgres "docker-entrypoint.s…" 50 minutes ago Up 50 minutes 0.0.0.0:5432->5432/tcp hoppscotch-backend-dev-db-1
|
||||
[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~/work/self-hosted/packages/hoppscotch-backend]1;..cotch-backend
|
||||
[0m[27m[24m[J[01;32m➜ [36mhoppscotch-backend[00m [01;34mgit:([31mfeat/user-authentication[34m) [33m✗[00m [K[?1h=[?2004hmmigrater [7mf48d44a76ccc[27m[12D[27mf[27m4[27m8[27md[27m4[27m4[27ma[27m7[27m6[27mc[27mc[27mc\[?1l>[?2004l
|
||||
|
||||
|
||||
[0m[27m[24m[J> [K[?1h=[?2004h[?2004l
|
||||
|
||||
[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~/work/self-hosted/packages/hoppscotch-backend]1;..cotch-backend
|
||||
[0m[27m[24m[J[01;31m➜ [36mhoppscotch-backend[00m [01;34mgit:([31mfeat/user-authentication[34m) [33m✗[00m [K[?1h=[?2004hmigrate f48d44a76ccc\ [?1l>[?2004l
|
||||
|
||||
]2;migrate f48d44a76ccc]1;migrate[?2004hroot@f48d44a76ccc:/usr/src/app# cd prisma/
|
||||
[?2004l
|
||||
[?2004hroot@f48d44a76ccc:/usr/src/app/prisma# pnpx prisma migrate dev
|
||||
[?2004l
|
||||
.pnpm-store/v3/tmp/dlx-2319 | Progress: resolved [96m1[39m, reused [96m0[39m, downloaded [96m0[39m, added [96m0[39m
|
||||
[1A.pnpm-store/v3/tmp/dlx-2319 | [32m+2[39m [32m+[39m[0K
|
||||
.pnpm-store/v3/tmp/dlx-2319 | Progress: resolved [96m1[39m, reused [96m0[39m, downloaded [96m0[39m, added [96m0[39m
|
||||
[1A.pnpm-store/v3/tmp/dlx-2319 | Progress: resolved [96m2[39m, reused [96m2[39m, downloaded [96m0[39m, added [96m2[39m, done
|
||||
[2mEnvironment variables loaded from ../.env[22m
|
||||
[2mPrisma schema loaded from schema.prisma[22m
|
||||
[2mDatasource "db": PostgreSQL database "hoppscotch", schema "public" at "dev-db:5432"[22m
|
||||
|
||||
Applying migration `20230112140525_auth`
|
||||
|
||||
The following migration(s) have been applied:
|
||||
|
||||
migrations/
|
||||
└─ 20230112140525_[36m[1mauth[22m[39m/
|
||||
└─ migration.sql
|
||||
|
||||
[32mYour database is now in sync with your schema.[39m
|
||||
|
||||
[?25lRunning generate... [2m(Use --skip-generate to skip the generators)[22m
|
||||
[?25l[2K[1A[2K[GRunning generate... - Prisma Client
|
||||
[?25l[2K[1A[2K[G✔ Generated [1mPrisma Client[22m (4.8.1 | library)[2m to ./../node_modules/.pnpm/@prisma+client@4.8.1_prisma@4.8.1/node_modules/@p[22m
|
||||
[2mrisma/client[22m in 121ms
|
||||
|
||||
|
||||
[?25h[?2004hroot@f48d44a76ccc:/usr/src/app/prisma# exit
|
||||
[?2004l
|
||||
exit
|
||||
[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~/work/self-hosted/packages/hoppscotch-backend]1;..cotch-backend
|
||||
[0m[27m[24m[J[01;32m➜ [36mhoppscotch-backend[00m [01;34mgit:([31mfeat/user-authentication[34m) [33m✗[00m [K[?1h=[?2004hccls[?1l>[?2004l
|
||||
|
||||
]2;clear]1;cls[H[2J[3J[1m[7m%[27m[1m[0m
|
||||
|
||||
]2;balubabu@LAPTOP-ME2SCHA9:~/work/self-hosted/packages/hoppscotch-backend]1;..cotch-backend
|
||||
[0m[27m[24m[J[01;32m➜ [36mhoppscotch-backend[00m [01;34mgit:([31mfeat/user-authentication[34m) [33m✗[00m [K[?1h=[?2004h[7mnpm install passport-google-oauth20[27m[35D[27mn[27mp[27mm[27m [27mi[27mn[27ms[27mt[27ma[27ml[27ml[27m [27mp[27ma[27ms[27ms[27mp[27mo[27mr[27mt[27m-[27mg[27mo[27mo[27mg[27ml[27me[27m-[27mo[27ma[27mu[27mt[27mh[27m2[27m0pnpm install passport-google-oauth20[35D[1C[1C[1C[1C[1C[1C[1C[1C[1C[1C[1C[1C[1C-passport-google-oauth20[23D-passport-google-oauth20[23Dspassport-google-oauth20[23Dapassport-google-oauth20[23Dvpassport-google-oauth20[23Depassport-google-oauth20[23D passport-google-oauth20[23D[?1l>[?2004l
|
||||
|
||||
]2;pnpm install --save passport-google-oauth20]1;pnpm../.. | Progress: resolved [96m0[39m, reused [96m1[39m, downloaded [96m0[39m, added [96m0[39m
|
||||
[1A[33m[39m[0K
|
||||
Reference in New Issue
Block a user