patch..
This commit is contained in:
+5
@@ -0,0 +1,5 @@
|
|||||||
|
ALTER TABLE "device_authorizations"
|
||||||
|
ADD COLUMN "registration_reference" TEXT;
|
||||||
|
|
||||||
|
CREATE INDEX "device_authorizations_registration_reference_idx"
|
||||||
|
ON "device_authorizations"("registration_reference");
|
||||||
@@ -237,6 +237,7 @@ model DeviceAuthorization {
|
|||||||
authUserName String? @map("auth_user_name")
|
authUserName String? @map("auth_user_name")
|
||||||
authUserRole String? @map("auth_user_role")
|
authUserRole String? @map("auth_user_role")
|
||||||
authUserRoles Json? @map("auth_user_roles")
|
authUserRoles Json? @map("auth_user_roles")
|
||||||
|
registrationReference String? @map("registration_reference")
|
||||||
device Json?
|
device Json?
|
||||||
expiresAt DateTime @map("expires_at") @db.Timestamptz(3)
|
expiresAt DateTime @map("expires_at") @db.Timestamptz(3)
|
||||||
approvedAt DateTime? @map("approved_at") @db.Timestamptz(3)
|
approvedAt DateTime? @map("approved_at") @db.Timestamptz(3)
|
||||||
@@ -245,6 +246,7 @@ model DeviceAuthorization {
|
|||||||
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
|
||||||
|
|
||||||
@@index([status, expiresAt])
|
@@index([status, expiresAt])
|
||||||
|
@@index([registrationReference])
|
||||||
@@map("device_authorizations")
|
@@map("device_authorizations")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import { IsNotEmpty, IsObject, IsOptional, IsString, ValidateNested } from 'clas
|
|||||||
import { ProvisioningDeviceDto } from './create-provisioning.dto';
|
import { ProvisioningDeviceDto } from './create-provisioning.dto';
|
||||||
|
|
||||||
export class CreateDeviceAuthorizationDto {
|
export class CreateDeviceAuthorizationDto {
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
registrationReference?: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
hostname?: string;
|
hostname?: string;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Body, Controller, Get, Headers, Post, UnauthorizedException } from '@nestjs/common';
|
import { Body, Controller, Get, Headers, Param, Post, UnauthorizedException } from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
import { CreateProvisioningDto } from './dto/create-provisioning.dto';
|
import { CreateProvisioningDto } from './dto/create-provisioning.dto';
|
||||||
import { CreateSessionProvisioningDto } from './dto/create-session-provisioning.dto';
|
import { CreateSessionProvisioningDto } from './dto/create-session-provisioning.dto';
|
||||||
import {
|
import {
|
||||||
ConsumeDeviceAuthorizationDto,
|
ConsumeDeviceAuthorizationDto,
|
||||||
|
CreateDeviceAuthorizationDto,
|
||||||
} from './dto/device-authorization.dto';
|
} from './dto/device-authorization.dto';
|
||||||
import { ProvisioningService } from './provisioning.service';
|
import { ProvisioningService } from './provisioning.service';
|
||||||
import type { ProvisioningResponse } from './provisioning.service';
|
import type { ProvisioningResponse } from './provisioning.service';
|
||||||
@@ -37,9 +38,11 @@ export class ProvisioningController {
|
|||||||
@Post('device-authorizations')
|
@Post('device-authorizations')
|
||||||
createDeviceAuthorization(
|
createDeviceAuthorization(
|
||||||
@Headers('authorization') authorization: string | undefined,
|
@Headers('authorization') authorization: string | undefined,
|
||||||
|
@Body() body: CreateDeviceAuthorizationDto,
|
||||||
) {
|
) {
|
||||||
return this.provisioningService.createDeviceAuthorization(
|
return this.provisioningService.createDeviceAuthorization(
|
||||||
this.getBearerToken(authorization),
|
this.getBearerToken(authorization),
|
||||||
|
body,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +69,17 @@ export class ProvisioningController {
|
|||||||
return this.provisioningService.consumeDeviceAuthorization(body);
|
return this.provisioningService.consumeDeviceAuthorization(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get('device-authorizations/registration/:reference')
|
||||||
|
getDeviceAuthorizationByRegistrationReference(
|
||||||
|
@Headers('authorization') authorization: string | undefined,
|
||||||
|
@Param('reference') reference: string,
|
||||||
|
) {
|
||||||
|
return this.provisioningService.getDeviceAuthorizationByRegistrationReference(
|
||||||
|
this.getBearerToken(authorization),
|
||||||
|
reference,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Post('ssh-keys/lookup')
|
@Post('ssh-keys/lookup')
|
||||||
listSshKeys(
|
listSshKeys(
|
||||||
@Headers('x-lms-gateway-token') token: string | undefined,
|
@Headers('x-lms-gateway-token') token: string | undefined,
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ import { createHash, randomBytes } from 'crypto';
|
|||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import { CreateProvisioningDto } from './dto/create-provisioning.dto';
|
import { CreateProvisioningDto } from './dto/create-provisioning.dto';
|
||||||
import { CreateSessionProvisioningDto } from './dto/create-session-provisioning.dto';
|
import { CreateSessionProvisioningDto } from './dto/create-session-provisioning.dto';
|
||||||
import { ConsumeDeviceAuthorizationDto } from './dto/device-authorization.dto';
|
import {
|
||||||
|
ConsumeDeviceAuthorizationDto,
|
||||||
|
CreateDeviceAuthorizationDto,
|
||||||
|
} from './dto/device-authorization.dto';
|
||||||
|
|
||||||
export type ProvisioningResponse = {
|
export type ProvisioningResponse = {
|
||||||
installTailscale: boolean;
|
installTailscale: boolean;
|
||||||
@@ -79,7 +82,10 @@ export class ProvisioningService {
|
|||||||
return this.createProvisioningForUser(provisioningDto, authUser);
|
return this.createProvisioningForUser(provisioningDto, authUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createDeviceAuthorization(accessToken: string | undefined) {
|
async createDeviceAuthorization(
|
||||||
|
accessToken: string | undefined,
|
||||||
|
input: CreateDeviceAuthorizationDto = {},
|
||||||
|
) {
|
||||||
const authUser = await this.authenticateAccessToken(accessToken);
|
const authUser = await this.authenticateAccessToken(accessToken);
|
||||||
const expiresInSeconds = Math.max(
|
const expiresInSeconds = Math.max(
|
||||||
60,
|
60,
|
||||||
@@ -100,6 +106,7 @@ export class ProvisioningService {
|
|||||||
authUserName: authUser.name ?? null,
|
authUserName: authUser.name ?? null,
|
||||||
authUserRole: authUser.role ?? null,
|
authUserRole: authUser.role ?? null,
|
||||||
authUserRoles: authUser.roles ? this.cleanJson(authUser.roles) : undefined,
|
authUserRoles: authUser.roles ? this.cleanJson(authUser.roles) : undefined,
|
||||||
|
registrationReference: this.cleanString(input.registrationReference),
|
||||||
expiresAt,
|
expiresAt,
|
||||||
approvedAt: new Date(),
|
approvedAt: new Date(),
|
||||||
},
|
},
|
||||||
@@ -155,6 +162,35 @@ export class ProvisioningService {
|
|||||||
return { cancelled: result.count > 0 };
|
return { cancelled: result.count > 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getDeviceAuthorizationByRegistrationReference(
|
||||||
|
accessToken: string | undefined,
|
||||||
|
reference: string,
|
||||||
|
) {
|
||||||
|
const authUser = await this.authenticateAccessToken(accessToken);
|
||||||
|
const registrationReference = this.cleanString(reference);
|
||||||
|
if (!registrationReference) {
|
||||||
|
throw new NotFoundException('Device authorization request was not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const authorization = await this.prisma.deviceAuthorization.findFirst({
|
||||||
|
where: {
|
||||||
|
registrationReference,
|
||||||
|
authUserId: authUser.id,
|
||||||
|
accountEmail: authUser.email,
|
||||||
|
},
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
select: {
|
||||||
|
status: true,
|
||||||
|
expiresAt: true,
|
||||||
|
consumedAt: true,
|
||||||
|
accountEmail: true,
|
||||||
|
device: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return authorization ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
async consumeDeviceAuthorization(body: ConsumeDeviceAuthorizationDto) {
|
async consumeDeviceAuthorization(body: ConsumeDeviceAuthorizationDto) {
|
||||||
const userCode = this.normalizeUserCode(body.userCode);
|
const userCode = this.normalizeUserCode(body.userCode);
|
||||||
const authorization = await this.prisma.deviceAuthorization.findUnique({
|
const authorization = await this.prisma.deviceAuthorization.findUnique({
|
||||||
@@ -202,7 +238,16 @@ export class ProvisioningService {
|
|||||||
const provisioning = await this.createProvisioningForUser(body, authUser);
|
const provisioning = await this.createProvisioningForUser(body, authUser);
|
||||||
await this.prisma.deviceAuthorization.update({
|
await this.prisma.deviceAuthorization.update({
|
||||||
where: { id: authorization.id },
|
where: { id: authorization.id },
|
||||||
data: { status: 'CONSUMED', consumedAt: new Date() },
|
data: {
|
||||||
|
status: 'CONSUMED',
|
||||||
|
consumedAt: new Date(),
|
||||||
|
device: this.cleanJson({
|
||||||
|
...(body.device ?? {}),
|
||||||
|
hostname: body.hostname ?? body.device?.hostname ?? null,
|
||||||
|
sshUser: body.sshUser ?? body.device?.sshUser ?? null,
|
||||||
|
workspaceRoot: body.workspaceRoot ?? body.device?.workspaceRoot ?? null,
|
||||||
|
}),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
return provisioning;
|
return provisioning;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user