Commit 91e00326 authored by Nauta, Lisanne's avatar Nauta, Lisanne
Browse files

Merge branch 'release/0.1.0'

parents acc71ab3 c8050b3a
This diff is collapsed.
{
"name": "api",
"version": "0.0.1",
"version": "0.1.0",
"description": "",
"author": "",
"author": "lisanne.nauta@wur.nl",
"private": true,
"license": "UNLICENSED",
"license": "CC-BY-NC-ND",
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "NODE_ENV=dev nest start --watch",
"start:dev:azure-staging": "NODE_ENV=azure-staging nest start --watch",
"start:debug": "nest start --debug --watch",
"start:stag": "NODE_ENV=stag node dist/main",
"start:dev:azure-test": "NODE_ENV=azure-test nest start --watch",
......@@ -26,8 +25,10 @@
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/.bin/typeorm",
"migration-generate": "npm run typeorm:cli -- migration:generate -n",
"migration:generate:dev": "NODE_ENV=dev npm run typeorm -- migration:generate --config src/ormconfig -n",
"migration:generate:azure-test": "NODE_ENV=azure-test npm run typeorm -- migration:generate --config src/ormconfig -n",
"migration:run:dev": "NODE_ENV=dev npm run typeorm -- migration:run --config src/ormconfig",
"migration:run:azure-test": "NODE_ENV=azure-test npm run typeorm -- migration:run --config src/ormconfig"
"migration:run:azure-test": "NODE_ENV=azure-test npm run typeorm -- migration:run --config src/ormconfig",
"migration:revert:dev": "NODE_ENV=dev npm run typeorm -- migration:revert --config src/ormconfig"
},
"dependencies": {
"@nestjs/axios": "0.0.3",
......@@ -35,6 +36,7 @@
"@nestjs/config": "^1.0.2",
"@nestjs/core": "^8.0.0",
"@nestjs/event-emitter": "^1.0.0",
"@nestjs/jwt": "^8.0.0",
"@nestjs/passport": "^8.0.1",
"@nestjs/platform-express": "^8.0.0",
"@nestjs/schedule": "^1.0.1",
......@@ -47,10 +49,9 @@
"dotenv": "^10.0.0",
"gdal-next": "^2.8.0",
"geojson": "^0.5.0",
"google-auth-library": "^7.10.0",
"luxon": "^2.0.2",
"passport": "^0.5.0",
"passport-google-oauth20": "^2.0.0",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"pg": "^8.7.1",
"reflect-metadata": "^0.1.13",
......@@ -67,7 +68,7 @@
"@types/express": "^4.17.13",
"@types/jest": "^27.0.1",
"@types/node": "^16.0.0",
"@types/passport-google-oauth20": "^2.0.10",
"@types/passport-jwt": "^3.0.6",
"@types/passport-local": "^1.0.34",
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^4.28.2",
......
import { Controller, Get } from '@nestjs/common';
import { ApiSecurity } from '@nestjs/swagger';
import { readFileSync } from 'fs';
import { AppService } from './app.service';
......@@ -10,10 +11,4 @@ export class AppController {
getHello() {
return {"status":"ok"}
}
@Get('swagger-doc')
getSwagger(){
const swagger_json = JSON.parse(readFileSync("src/swagger.json", {encoding: 'utf-8'}));
return swagger_json;
}
}
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './user/user.module';
import { ConfigModule } from '@nestjs/config';
import { AuthModule } from './auth/auth.module';
import { LocationModule } from './location/location.module';
import { TaskModule } from './task/task.module';
import { Module } from '@nestjs/common';
......@@ -15,6 +14,7 @@ import { RegionModule } from './region/region.module';
import { join } from 'path';
import { DatabaseConfig } from "./ormconfig";
import { LoggerModule } from './logger/logger.module';
import { AuthModule } from './auth/auth.module';
/* const ormconfig : TypeOrmModuleOptions= {
type: 'postgres',
......@@ -33,7 +33,7 @@ import { LoggerModule } from './logger/logger.module';
@Module({
imports: [EventEmitterModule.forRoot() ,ConfigModule.forRoot({ envFilePath: `${process.env.NODE_ENV}.env` }),
TypeOrmModule.forRoot(DatabaseConfig), UserModule, AuthModule, LocationModule, TaskModule, DataModule, ObservationModule,
TypeOrmModule.forRoot(DatabaseConfig), UserModule, AuthModule ,LocationModule, TaskModule, DataModule, ObservationModule,
DataSourceModule, RegionModule, LoggerModule],
controllers: [AppController],
providers: [AppService],
......
import { Test, TestingModule } from '@nestjs/testing';
import { AuthController } from './auth.controller';
describe('AuthController', () => {
let controller: AuthController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [AuthController],
}).compile();
controller = module.get<AuthController>(AuthController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
import { Body, Controller, Get, HttpCode, Post, UnauthorizedException } from '@nestjs/common';
import { OAuth2Client } from 'google-auth-library';
import { Body, Controller, forwardRef, HttpCode, Inject, Post, Request, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { ApiTags, ApiResponse, ApiOkResponse, ApiUnauthorizedResponse } from '@nestjs/swagger';
import { PhoneUserDto } from './phone/phone-user.dto';
import { User } from 'src/user/user.entity';
import { ApiProperty } from '@nestjs/swagger';
import { ApiTags, ApiOkResponse, ApiUnauthorizedResponse } from '@nestjs/swagger';
import { AuthResponse } from './models/auth-response';
import { LocalAuthGuard } from './guards/local-auth.guard';
import { RequestWithUser } from './interfaces/request-with-user.interface';
export class TokenResponse {
export class JwtCredentials {
constructor(){}
@ApiProperty()
access_token: number;
}
username: string;
export class SocialLoginRequest {
constructor(){}
password: string;
@ApiProperty()
user: any;
}
@ApiTags('auth')
@Controller('auth')
export class AuthController {
private googleClient: OAuth2Client;
constructor(private readonly authService: AuthService) {
this.googleClient = new OAuth2Client(process.env.GOOGLE_WEB_CLIENT_ID)
}
@HttpCode(200)
@Post('google')
@ApiOkResponse({
type: TokenResponse
})
async googleAuth(@Body() body: SocialLoginRequest ): Promise<TokenResponse> {
console.log(body);
const ticket = await this.googleClient.verifyIdToken({
idToken: body.user.idToken,
audience:process.env.GOOGLE_WEB_CLIENT_ID
})
const payload = ticket.getPayload();
const userid = payload['sub'];
return {access_token: 1234};
constructor(@Inject(forwardRef(() => AuthService))
private authService: AuthService) {
}
/* @UseGuards(AuthGuard('local')) */
@Post('phone')
@UseGuards(LocalAuthGuard)
@Post('login')
@HttpCode(200)
@ApiOkResponse({
type: User
type: AuthResponse
})
@ApiUnauthorizedResponse({
})
phoneAuth(@Body() phoneUser: PhoneUserDto ) : Promise<User> {
return this.authService.phoneLogin(phoneUser);
login(@Request() req: RequestWithUser, @Body() body: JwtCredentials) {
//return this.authService.phoneLogin(phoneUser);
//return req.user;
const result = this.authService.login(req.user);
const response = {user: result.user, access_token: result.access_token} as AuthResponse;
return response;
}
......
......@@ -2,12 +2,19 @@ import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UserModule } from 'src/user/user.module';
import { OAuth2Client } from 'google-auth-library';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { LocalStrategy } from './strategies/local.strategy';
import { JwtStrategy } from './strategies/jwt.strategy';
@Module({
imports:[UserModule, PassportModule],
providers: [AuthService, OAuth2Client],
controllers: [AuthController]
imports:[UserModule,PassportModule,
JwtModule.register({
secret: process.env['JWT_SECRET_KEY'],
signOptions: { expiresIn: '1d' },
})],
providers: [AuthService, LocalStrategy, JwtStrategy],
controllers: [AuthController],
exports:[AuthService]
})
export class AuthModule {}
import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from './auth.service';
describe('AuthService', () => {
let service: AuthService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [AuthService],
}).compile();
service = module.get<AuthService>(AuthService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { User } from 'src/user/user.entity';
import { UserService } from 'src/user/user.service';
import { PhoneUserDto } from './phone/phone-user.dto';
@Injectable()
@Injectable({})
export class AuthService {
constructor(private userService: UserService){}
async googleLogin(req: any) {
console.log("googleLogin")
if (!req.user) {
throw new UnauthorizedException();
}
else{
let user = await this.userService.getByEmail(req.user.email);
/* return req.user; */
if(!user){
//user = await this.userService.create();
}
return user;
constructor(private userService: UserService, private jwtService: JwtService){}
}
}
async phoneLogin(phoneUser: PhoneUserDto){
let user = await this.userService.getByPhone(phoneUser.phoneNumber);
if(!user){
throw new UnauthorizedException();
}
else{
async validateUser(username: string, pass: string): Promise<User> {
const user = await this.userService.getByPhone(username);
if (user && user.phonenumber === pass) {
//const { phonenumber, ...result } = user;
return user;
}
return null;
}
login(user: User) {
const payload = { sub: user.id };
const access_token = this.jwtService.sign(payload)
const result = {user: user, access_token: access_token}
return result;
/* return {
access_token: this.jwtService.sign(payload),
}; */
}
verifyUser(access_token:string){
const decodedJwtAccessToken = this.jwtService.decode(access_token);
return decodedJwtAccessToken.sub;
}
}
export enum UserRole {
User = 'User',
Admin = 'Admin',
}
import { Injectable } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { Strategy, VerifyCallback } from "passport-google-oauth20";
@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
constructor() {
super({
clientID: process.env.GOOGLE_WEB_CLIENT_ID,
clientSecret: process.env.GOOGLE_WEB_CLIENT_SECRET,
callbackURL: 'http://localhost:3000/auth/google/redirect',
scope: ['email', 'profile']
});
}
async validate (accessToken: string, refreshToken: string, profile: any, done: VerifyCallback): Promise<any> {
const { id, name, emails, photos } = profile;
const user = {
provider: 'google',
providerId: id,
email: emails[0].value,
firstName: name.givenName,
lastName: name.familyName,
picture: photos[0].value,
profileId: profile.id,
accessToken: accessToken,
refreshToken: refreshToken
}
done(null, user);
}
}
\ No newline at end of file
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { Observable } from 'rxjs';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
return super.canActivate(context);
}
}
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {
}
import { CanActivate, ExecutionContext, Injectable, mixin, Type } from '@nestjs/common';
import { Observable } from 'rxjs';
import { UserRole } from '../enums/user-role';
import { RequestWithUser } from '../interfaces/request-with-user.interface';
import { JwtAuthGuard } from './jwt-auth.guard';
const UserRoleGuard = (role: UserRole): Type<CanActivate> => {
class RoleGuardMixin extends JwtAuthGuard {
async canActivate(context: ExecutionContext) {
await super.canActivate(context);
const request = context.switchToHttp().getRequest<RequestWithUser>();
const user = request.user;
return user.roles.includes(role);
}
}
return mixin(RoleGuardMixin);
}
export default UserRoleGuard;
import { Request } from 'express';
import { User } from 'src/user/user.entity';
export interface RequestWithUser extends Request{
user: User
}
import { ApiProperty } from "@nestjs/swagger";
import { User } from "src/user/user.entity";
export class AuthResponse {
@ApiProperty()
user: User;
@ApiProperty()
access_token: string;
}
import { ApiProperty } from '@nestjs/swagger';
export class PhoneUserDto{
constructor(){}
@ApiProperty()
phoneNumber: string;
}
\ No newline at end of file
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, NotFoundException } from '@nestjs/common';
import { UserService } from 'src/user/user.service';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private userService: UserService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env['JWT_SECRET_KEY'],
});
}
async validate(payload: any) {
const user = await this.userService.getById(payload.sub);
if(!user){
throw new NotFoundException();
}
return user;
};
}
\ No newline at end of file
import { Injectable, UnauthorizedException } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { Strategy } from "passport-local";
import { AuthService } from "../auth.service";
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy){
constructor(public authService: AuthService) {
super({});
}
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
\ No newline at end of file
import { Test, TestingModule } from '@nestjs/testing';
import { ForecastController } from './forecast.controller';
describe('ForecastController', () => {
let controller: ForecastController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [ForecastController],
}).compile();
controller = module.get<ForecastController>(ForecastController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment