Skip to content

Commit 6e37c4e

Browse files
authored
Merge pull request #31 from CodeLog-Development/hotfix/android
Merge hotfix/android into main
2 parents 934f5f4 + 739057f commit 6e37c4e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1127
-458
lines changed

.github/workflows/firebase-hosting-merge.yml

Lines changed: 0 additions & 21 deletions
This file was deleted.

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# See http://help.github.com/ignore-files/ for more about ignoring files.
22

3-
firebase-debug.log
3+
*-debug.log
44
.firebase/*.cache
55
# api/firebase-service-account.json
66

README.md

Lines changed: 11 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,16 @@
1-
# Gatekeeper
2-
3-
<a alt="Nx logo" href="https://nx.dev" target="_blank" rel="noreferrer"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-logo.png" width="45"></a>
4-
5-
**This workspace has been generated by [Nx, a Smart, fast and extensible build system.](https://nx.dev)**
6-
7-
## Generate code
8-
9-
If you happen to use Nx plugins, you can leverage code generators that might come with it.
10-
11-
Run `nx list` to get a list of available plugins and whether they have generators. Then run `nx list <plugin-name>` to see what generators are available.
12-
13-
Learn more about [Nx generators on the docs](https://nx.dev/plugin-features/use-code-generators).
14-
15-
## Running tasks
16-
17-
To execute tasks with Nx use the following syntax:
18-
19-
```
20-
nx <target> <project> <...options>
21-
```
1+
[![Build and test](https://github.com/CodeLog-Development/gatekeeper/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/CodeLog-Development/gatekeeper/actions/workflows/build-and-test.yml)
222

23-
You can also run multiple targets:
24-
25-
```
26-
nx run-many -t <target1> <target2>
27-
```
28-
29-
..or add `-p` to filter specific projects
30-
31-
```
32-
nx run-many -t <target1> <target2> -p <proj1> <proj2>
33-
```
34-
35-
Targets can be defined in the `package.json` or `projects.json`. Learn more [in the docs](https://nx.dev/core-features/run-tasks).
36-
37-
## Want better Editor Integration?
38-
39-
Have a look at the [Nx Console extensions](https://nx.dev/nx-console). It provides autocomplete support, a UI for exploring and running tasks & generators, and more! Available for VSCode, IntelliJ and comes with a LSP for Vim users.
40-
41-
## Ready to deploy?
42-
43-
Just run `nx build demoapp` to build the application. The build artifacts will be stored in the `dist/` directory, ready to be deployed.
44-
45-
## Set up CI!
3+
# Gatekeeper
464

47-
Nx comes with local caching already built-in (check your `nx.json`). On CI you might want to go a step further.
5+
## Building
486

49-
- [Set up remote caching](https://nx.dev/core-features/share-your-cache)
50-
- [Set up task distribution across multiple machines](https://nx.dev/core-features/distribute-task-execution)
51-
- [Learn more how to setup CI](https://nx.dev/recipes/ci)
7+
1. The first step is to run `yarn install` in the project root to download and build
8+
all dependencies.
9+
2. Next, you can run `yarn nx run app:build:production` and `yarn nx run api:build:production`
10+
to build the projects.
5211

53-
## Connect with us!
12+
## Development
5413

55-
- [Join the community](https://nx.dev/community)
56-
- [Subscribe to the Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
57-
- [Follow us on Twitter](https://twitter.com/nxdevtools)
14+
- To run the backend and frontend in a dev environment, start up the emulators for the backend using
15+
`yarn nx run api:emulators`.
16+
- You can then start the frontend with `yarn nx serve app`

api/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"name": "@gatekeeper/api",
3-
"version": "0.0.1",
3+
"version": "0.1.0",
44
"dependencies": {
5-
"@aws-sdk/client-ec2": "3.422.0",
5+
"@aws-sdk/client-ec2": "^3.422.0",
66
"@nestjs/common": "^10.2.6",
77
"@nestjs/config": "^3.1.1",
88
"@nestjs/core": "^10.2.6",
@@ -16,7 +16,8 @@
1616
"tslib": "^2.3.0"
1717
},
1818
"scripts": {
19-
"serve": "cd .. && yarn nx build api && yarn firebase serve"
19+
"serve": "cd .. && yarn nx build api && yarn firebase serve",
20+
"emulators": "cd .. && yarn nx build api && yarn firebase emulators:start"
2021
},
2122
"type": "commonjs",
2223
"main": "./src/index.js",

api/project.json

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
"targets": {
77
"build": {
88
"executor": "@nx/js:tsc",
9-
"outputs": [
10-
"{options.outputPath}"
11-
],
9+
"outputs": ["{options.outputPath}"],
1210
"options": {
1311
"outputPath": "dist/api",
1412
"tsConfig": "api/tsconfig.lib.json",
@@ -27,21 +25,14 @@
2725
},
2826
"lint": {
2927
"executor": "@nx/linter:eslint",
30-
"outputs": [
31-
"{options.outputFile}"
32-
],
28+
"outputs": ["{options.outputFile}"],
3329
"options": {
34-
"lintFilePatterns": [
35-
"api/**/*.ts",
36-
"api/package.json"
37-
]
30+
"lintFilePatterns": ["api/**/*.ts", "api/package.json"]
3831
}
3932
},
4033
"test": {
4134
"executor": "@nx/jest:jest",
42-
"outputs": [
43-
"{workspaceRoot}/coverage/{projectRoot}"
44-
],
35+
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
4536
"options": {
4637
"jestConfig": "api/jest.config.ts",
4738
"passWithNoTests": true
@@ -58,6 +49,12 @@
5849
"options": {
5950
"script": "serve"
6051
}
52+
},
53+
"emulators": {
54+
"executor": "nx:run-script",
55+
"options": {
56+
"script": "emulators"
57+
}
6158
}
6259
},
6360
"tags": []

api/src/index.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,26 @@ export * from './lib/index';
1010
const expressServer = express();
1111

1212
const createFunction = async (
13-
expressInstance: express.Express
13+
expressInstance: express.Express,
1414
): Promise<void> => {
1515
const app = await NestFactory.create(
1616
ApiModule,
1717
new ExpressAdapter(expressInstance),
1818
{
1919
cors: {
20-
origin: [
21-
'https://codelog-mc.web.app',
22-
'https://us-central1-codelog-mc.cloudfunctions.net',
23-
'http://localhost',
24-
],
25-
methods: ['GET', 'POST', 'OPTIONS', 'PUT', 'DELETE'],
20+
origin: true,
21+
methods: ['GET', 'POST', 'OPTIONS', 'PUT', 'DELETE', 'PATCH'],
2622
credentials: true,
2723
},
28-
}
24+
},
2925
);
3026
app.use(cookieParser());
3127
await app.init();
3228
};
3329

34-
export const api = functions.https.onRequest(async (request, response) => {
30+
export const api = new functions.FunctionBuilder({
31+
regions: ['europe-west2'],
32+
}).https.onRequest(async (request, response) => {
3533
await createFunction(expressServer);
3634
expressServer(request, response);
3735
});

api/src/lib/api.interface.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1+
import * as express from 'express';
2+
import { User } from './user';
3+
14
export interface ApiResponse {
25
success: boolean;
36
message: string | undefined;
47
}
8+
9+
export interface Request extends express.Request {
10+
user?: User;
11+
}

api/src/lib/auth/auth.middleware.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { Injectable, NestMiddleware } from '@nestjs/common';
22
import { ModuleRef } from '@nestjs/core';
3-
import { NextFunction, Request, Response } from 'express';
3+
import { NextFunction, Response } from 'express';
44
import { UserService } from '../user/user.service';
5+
import { User } from '../user';
6+
import { Request } from '../api.interface';
57

68
@Injectable()
79
export class AuthenticationMiddleware implements NestMiddleware {
@@ -17,8 +19,9 @@ export class AuthenticationMiddleware implements NestMiddleware {
1719
} else {
1820
this.userService
1921
.checkCookie(authCookie)
20-
.then((isValid) => {
21-
if (isValid) {
22+
.then((user: User | undefined) => {
23+
if (user?.verified) {
24+
req.user = user;
2225
next();
2326
} else {
2427
res.status(401).end();
@@ -27,7 +30,7 @@ export class AuthenticationMiddleware implements NestMiddleware {
2730
.catch((e) => {
2831
console.error(
2932
' ~ auth.middleware.ts:25 → Failed to check cookie',
30-
e
33+
e,
3134
);
3235
res.status(500).end();
3336
});

api/src/lib/user/user.controller.ts

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
1-
import { Controller, Post, Body, Res } from '@nestjs/common';
2-
import { AuthRequest, NewUser } from './user.interface';
1+
import {
2+
Controller,
3+
Post,
4+
Body,
5+
Res,
6+
Patch,
7+
Get,
8+
Param,
9+
Req,
10+
} from '@nestjs/common';
11+
import {
12+
AuthRequest,
13+
ChangePasswordRequest,
14+
NewUser,
15+
UserInfoResponse,
16+
validatePassword,
17+
} from './user.interface';
318
import { UserService } from './user.service';
419
import { Response } from 'express';
20+
import { Request } from '../api.interface';
521
import { ApiResponse } from '../api.interface';
22+
import * as argon2 from 'argon2';
623

724
export const EMAIL_REGEX =
825
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
@@ -11,27 +28,85 @@ export const EMAIL_REGEX =
1128
export class UserController {
1229
constructor(private userService: UserService) { }
1330

31+
@Get('info')
32+
async getUserInfo(@Req() request: Request): Promise<UserInfoResponse> {
33+
console.log(' 🚀 ~ user.controller.ts:33 → User info', request.user);
34+
if (!request.user) {
35+
return { success: false, message: 'Not logged in' };
36+
}
37+
return {
38+
success: true,
39+
message: 'User info returned',
40+
user: {
41+
username: request.user.username,
42+
email: request.user.email,
43+
verified: request.user.verified,
44+
},
45+
};
46+
}
47+
48+
@Patch('/password')
49+
async changePassword(
50+
@Body() input: ChangePasswordRequest,
51+
): Promise<ApiResponse> {
52+
const passwordValidation = validatePassword(input.newPassword);
53+
if (passwordValidation !== undefined) {
54+
return { success: false, message: passwordValidation };
55+
}
56+
57+
if (input.newPassword !== input.confirm) {
58+
return { success: false, message: "Confirmation password doesn't match" };
59+
}
60+
61+
try {
62+
const userRef = await this.userService.findUserByUsernameRef(
63+
input.username,
64+
);
65+
66+
const user = (await userRef?.get())?.data();
67+
68+
if (!user || !userRef) {
69+
return {
70+
success: false,
71+
message: 'The specified user could not be found',
72+
};
73+
}
74+
75+
if (!(await argon2.verify(user.passwordHash, input.currentPassword))) {
76+
return {
77+
success: false,
78+
message: 'The supplied current password was incorrect',
79+
};
80+
}
81+
82+
await this.userService.changePassword(userRef, input.newPassword);
83+
return { success: true, message: 'Password updated' };
84+
} catch (e) {
85+
return { success: false, message: 'Failed to update password' };
86+
}
87+
}
88+
1489
@Post()
1590
async createUser(
1691
@Body() newUser: NewUser,
17-
@Res({ passthrough: true }) res: Response
92+
@Res({ passthrough: true }) res: Response,
1893
): Promise<ApiResponse> {
1994
try {
2095
if (!EMAIL_REGEX.test(newUser.email)) {
2196
return { success: false, message: 'Invalid email' };
2297
}
2398

2499
const existingEmail = await this.userService.findUserByEmail(
25-
newUser.email
100+
newUser.email,
26101
);
27102
const existingUsername = await this.userService.findUserByUsername(
28-
newUser.username
103+
newUser.username,
29104
);
30105

31106
console.log(
32107
'🚀 ~ user.controller.ts:31 → Existing users (undefined is good): ',
33108
existingEmail,
34-
existingUsername
109+
existingUsername,
35110
);
36111

37112
if (existingEmail !== undefined || existingUsername !== undefined) {
@@ -65,10 +140,10 @@ export class UserController {
65140
@Post('/login')
66141
async login(
67142
@Body() loginRequest: AuthRequest,
68-
@Res({ passthrough: true }) res: Response
143+
@Res({ passthrough: true }) res: Response,
69144
): Promise<ApiResponse> {
70145
const user = await this.userService.findUserByUsername(
71-
loginRequest.username
146+
loginRequest.username,
72147
);
73148

74149
if (!user) {
@@ -81,7 +156,7 @@ export class UserController {
81156

82157
const result = await this.userService.authenticate(
83158
loginRequest.username,
84-
loginRequest.password
159+
loginRequest.password,
85160
);
86161

87162
if (result === undefined) {

0 commit comments

Comments
 (0)