resolve conflicts

This commit is contained in:
unknown
2024-10-08 10:59:31 +03:00
53 changed files with 1009 additions and 1535 deletions

View File

@ -1,6 +1,4 @@
import { Module } from '@nestjs/common';
import { AuthenticationController } from './controllers/authentication.controller';
import { AuthenticationService } from './services/authentication.service';
import { ConfigModule } from '@nestjs/config';
import { UserRepositoryModule } from '@app/common/modules/user/user.repository.module';
import { CommonModule } from '../../libs/common/src';
@ -16,9 +14,8 @@ import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
@Module({
imports: [ConfigModule, UserRepositoryModule, CommonModule],
controllers: [AuthenticationController, UserAuthController],
controllers: [UserAuthController],
providers: [
AuthenticationService,
UserAuthService,
UserRepository,
UserSessionRepository,
@ -26,6 +23,6 @@ import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
UserRoleRepository,
RoleTypeRepository,
],
exports: [AuthenticationService, UserAuthService],
exports: [UserAuthService],
})
export class AuthenticationModule {}

View File

@ -1,17 +0,0 @@
import { Controller, Post } from '@nestjs/common';
import { AuthenticationService } from '../services/authentication.service';
import { ApiTags } from '@nestjs/swagger';
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
@Controller({
version: EnableDisableStatusEnum.ENABLED,
path: 'authentication',
})
@ApiTags('Tuya Auth')
export class AuthenticationController {
constructor(private readonly authenticationService: AuthenticationService) {}
@Post('auth2')
async Authentication() {
return await this.authenticationService.main();
}
}

View File

@ -1,2 +1 @@
export * from './authentication.controller';
export * from './user-auth.controller';

View File

@ -84,7 +84,7 @@ export class UserAuthController {
@ApiBearerAuth()
@UseGuards(SuperAdminRoleGuard)
@Get('user/list')
@Get('user')
async userList() {
const userList = await this.userAuthService.userList();
return {

View File

@ -41,5 +41,5 @@ export class UserSignUpDto {
@IsString()
@IsOptional()
public regionUuid: string;
public regionUuid?: string;
}

View File

@ -1,19 +1,23 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { IsEmail, IsOptional, IsString } from 'class-validator';
export class UserLoginDto {
@ApiProperty()
@IsEmail()
@IsNotEmpty()
email: string;
@IsOptional()
email?: string;
@ApiProperty()
@IsString()
@IsOptional()
password: string;
password?: string;
@ApiProperty()
@IsString()
@IsOptional()
regionUuid?: string;
@IsOptional()
@IsString()
googleCode?: string;
}

View File

@ -1,120 +0,0 @@
import { Injectable } from '@nestjs/common';
import * as qs from 'qs';
import * as crypto from 'crypto';
import { ConfigService } from '@nestjs/config';
import axios from 'axios';
@Injectable()
export class AuthenticationService {
private token: string;
private deviceId: string;
private accessKey: string;
private secretKey: string;
constructor(private readonly configService: ConfigService) {
(this.deviceId = this.configService.get<string>('auth-config.DEVICE_ID')),
(this.accessKey = this.configService.get<string>(
'auth-config.ACCESS_KEY',
)),
(this.secretKey = this.configService.get<string>(
'auth-config.SECRET_KEY',
));
}
async main() {
await this.getToken();
const data = await this.getDeviceInfo(this.deviceId);
console.log('fetch success: ', JSON.stringify(data));
return JSON.stringify(data);
}
async getToken() {
const method = 'GET';
const timestamp = Date.now().toString();
const signUrl = 'https://openapi.tuyaeu.com/v1.0/token?grant_type=1';
const contentHash = crypto.createHash('sha256').update('').digest('hex');
const stringToSign = [method, contentHash, '', signUrl].join('\n');
const signStr = this.accessKey + timestamp + stringToSign;
const headers = {
t: timestamp,
sign_method: 'HMAC-SHA256',
client_id: this.accessKey,
sign: await this.encryptStr(signStr, this.secretKey),
};
const { data: login } = await axios.get(
'https://openapi.tuyaeu.com/v1.0/token',
{
params: {
grant_type: 1,
},
headers,
},
);
if (!login || !login.success) {
throw new Error(`fetch failed: ${login.msg}`);
}
this.token = login.result.access_token;
}
async getDeviceInfo(deviceId: string) {
const query = {};
const method = 'POST';
const url = `https://openapi.tuyaeu.com/v1.0/devices/${deviceId}/commands`;
const reqHeaders: { [k: string]: string } = await this.getRequestSign(
url,
method,
{},
query,
);
const { data } = await axios.post(url, {}, reqHeaders);
if (!data || !data.success) {
throw new Error(`request api failed: ${data.msg}`);
}
return data;
}
async encryptStr(str: string, secret: string): Promise<string> {
return crypto
.createHmac('sha256', secret)
.update(str, 'utf8')
.digest('hex')
.toUpperCase();
}
async getRequestSign(
path: string,
method: string,
query: { [k: string]: any } = {},
body: { [k: string]: any } = {},
) {
const t = Date.now().toString();
const [uri, pathQuery] = path.split('?');
const queryMerged = Object.assign(query, qs.parse(pathQuery));
const sortedQuery: { [k: string]: string } = {};
Object.keys(queryMerged)
.sort()
.forEach((i) => (sortedQuery[i] = query[i]));
const querystring = decodeURIComponent(qs.stringify(sortedQuery));
const url = querystring ? `${uri}?${querystring}` : uri;
const contentHash = crypto
.createHash('sha256')
.update(JSON.stringify(body))
.digest('hex');
const stringToSign = [method, contentHash, '', url].join('\n');
const signStr = this.accessKey + this.token + t + stringToSign;
return {
t,
path: url,
client_id: 'this.accessKey',
sign: await this.encryptStr(signStr, this.secretKey),
sign_method: 'HMAC-SHA256',
access_token: this.token,
};
}
}

View File

@ -1,2 +1 @@
export * from './authentication.service';
export * from './user-auth.service';

View File

@ -3,7 +3,6 @@ import {
BadRequestException,
ForbiddenException,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { UserSignUpDto } from '../dtos/user-auth.dto';
import { HelperHashService } from '../../../libs/common/src/helper/services';
@ -19,6 +18,7 @@ import * as argon2 from 'argon2';
import { differenceInSeconds } from '@app/common/helper/differenceInSeconds';
import { LessThan, MoreThan } from 'typeorm';
import { ConfigService } from '@nestjs/config';
import { UUID } from 'typeorm/driver/mongodb/bson.typings';
@Injectable()
export class UserAuthService {
@ -89,13 +89,38 @@ export class UserAuthService {
async userLogin(data: UserLoginDto) {
try {
const user = await this.authService.validateUser(
data.email,
data.password,
data.regionUuid,
);
if (!user) {
throw new UnauthorizedException('Invalid login credentials.');
let user;
if (data.googleCode) {
const googleUserData = await this.authService.login({
googleCode: data.googleCode,
});
const userExists = await this.userRepository.exists({
where: {
email: googleUserData['email'],
},
});
user = await this.userRepository.findOne({
where: {
email: googleUserData['email'],
},
});
if (!userExists) {
await this.signUp({
email: googleUserData['email'],
firstName: googleUserData['given_name'],
lastName: googleUserData['family_name'],
password: googleUserData['email'],
});
}
data.email = googleUserData['email'];
data.password = googleUserData['password'];
}
if (!data.googleCode) {
user = await this.authService.validateUser(
data.email,
data.password,
data.regionUuid,
);
}
const session = await Promise.all([
await this.sessionRepository.update(
@ -110,7 +135,7 @@ export class UserAuthService {
isLoggedOut: false,
}),
]);
return await this.authService.login({
const res = await this.authService.login({
email: user.email,
userId: user.uuid,
uuid: user.uuid,
@ -119,6 +144,7 @@ export class UserAuthService {
}),
sessionId: session[1].uuid,
});
return res;
} catch (error) {
throw new BadRequestException('Invalid credentials');
}