Skip to content

Commit f859033

Browse files
committed
add user migration, fix userId in Audit
1 parent 7a2ed36 commit f859033

File tree

10 files changed

+147
-81
lines changed

10 files changed

+147
-81
lines changed

server/prisma/schema.prisma

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ model User {
7070
username String @unique
7171
firstName String?
7272
lastName String?
73-
company String?
74-
location String?
7573
email String @unique
7674
emailVerified DateTime?
7775
password String

server/src/apps/apps.controller.ts

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
Post,
1212
Put,
1313
UseGuards,
14+
Request,
1415
} from '@nestjs/common';
1516
import { AppsService } from './apps.service';
1617
import { IUser } from '../auth/auth.interface';
@@ -65,6 +66,7 @@ export class AppsController {
6566
@Param('phase') phase: string,
6667
@Param('app') appName: string,
6768
@Body() app: any,
69+
@Request() req: any,
6870
) {
6971
if (appName !== 'new') {
7072
const msg = 'App name does not match the URL';
@@ -82,12 +84,10 @@ export class AppsController {
8284
throw new HttpException(msg, HttpStatus.BAD_REQUEST);
8385
}
8486

85-
//TODO: Migration -> this is a mock user
8687
const user: IUser = {
87-
id: 1,
88-
method: 'local',
89-
username: 'admin',
90-
apitoken: '1234567890',
88+
id: req.user.userId,
89+
strategy: req.user.strategy,
90+
username: req.user.username,
9191
};
9292
return this.appsService.createApp(app, user);
9393
}
@@ -108,6 +108,7 @@ export class AppsController {
108108
@Param('app') appName: string,
109109
@Param('resourceVersion') resourceVersion: string,
110110
@Body() app: any,
111+
@Request() req: any,
111112
) {
112113
if (appName !== app.name) {
113114
const msg =
@@ -116,12 +117,10 @@ export class AppsController {
116117
throw new HttpException(msg, HttpStatus.BAD_REQUEST);
117118
}
118119

119-
//TODO: Migration -> this is a mock user
120120
const user: IUser = {
121-
id: 1,
122-
method: 'local',
123-
username: 'admin',
124-
apitoken: '1234567890',
121+
id: req.user.userId,
122+
strategy: req.user.strategy,
123+
username: req.user.username,
125124
};
126125
return this.appsService.updateApp(app, resourceVersion, user);
127126
}
@@ -140,13 +139,13 @@ export class AppsController {
140139
@Param('pipeline') pipeline: string,
141140
@Param('phase') phase: string,
142141
@Param('app') app: string,
142+
@Request() req: any,
143143
) {
144-
//TODO: Migration -> this is a mock user
144+
145145
const user: IUser = {
146-
id: 1,
147-
method: 'local',
148-
username: 'admin',
149-
apitoken: '1234567890',
146+
id: req.user.userId,
147+
strategy: req.user.strategy,
148+
username: req.user.username,
150149
};
151150
return this.appsService.deleteApp(pipeline, phase, app, user);
152151
}
@@ -201,13 +200,12 @@ export class AppsController {
201200
@Param('pipeline') pipeline: string,
202201
@Param('phase') phase: string,
203202
@Param('app') app: string,
203+
@Request() req: any,
204204
) {
205-
//TODO: Migration -> this is a mock user
206205
const user: IUser = {
207-
id: 1,
208-
method: 'local',
209-
username: 'admin',
210-
apitoken: '1234567890',
206+
id: req.user.userId,
207+
strategy: req.user.strategy,
208+
username: req.user.username,
211209
};
212210

213211
return this.appsService.restartApp(pipeline, phase, app, user);
@@ -245,6 +243,7 @@ export class AppsController {
245243
@Param('phase') phase: string,
246244
@Param('app') app: string,
247245
@Body() body: any,
246+
@Request() req: any,
248247
) {
249248
if (process.env.KUBERO_CONSOLE_ENABLED !== 'true') {
250249
const msg = 'Console is not enabled';
@@ -266,11 +265,11 @@ export class AppsController {
266265
Logger.error(msg);
267266
throw new HttpException(msg, HttpStatus.BAD_REQUEST);
268267
}
268+
269269
const user: IUser = {
270-
id: 1,
271-
method: 'local',
272-
username: 'admin',
273-
apitoken: '1234567890',
270+
id: req.user.userId,
271+
strategy: req.user.strategy,
272+
username: req.user.username,
274273
};
275274

276275
const podName = body.podName;

server/src/apps/apps.service.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export class AppsService {
8686

8787
const m = {
8888
name: 'newApp',
89-
user: user.username,
89+
user: user.id,
9090
resource: 'app',
9191
action: 'create',
9292
severity: 'normal',
@@ -222,7 +222,7 @@ export class AppsService {
222222

223223
const m = {
224224
name: 'deleteApp',
225-
user: user.username,
225+
user: user.id,
226226
resource: 'app',
227227
action: 'delete',
228228
severity: 'normal',
@@ -570,7 +570,7 @@ export class AppsService {
570570

571571
const m = {
572572
name: 'restartApp',
573-
user: user.username,
573+
user: user.id,
574574
resource: 'app',
575575
action: 'restart',
576576
severity: 'normal',
@@ -629,7 +629,7 @@ export class AppsService {
629629

630630
const m = {
631631
name: 'updateApp',
632-
user: user.username,
632+
user: user.id,
633633
resource: 'app',
634634
action: 'update',
635635
severity: 'normal',

server/src/auth/auth.interface.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export type IUser = {
2-
id: number;
3-
method: string;
2+
id: string;
3+
strategy: string;
44
username: string;
55
apitoken?: string;
66
};

server/src/auth/strategies/jwt.guard.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export class JwtAuthGuard extends AuthGuard('jwt') {
3232
this.logger.warn('Authentication failed: ' + info);
3333
throw err || new UnauthorizedException();
3434
}
35+
//this.logger.debug(user, info);
3536
return user;
3637
}
3738
}

server/src/auth/strategies/jwt.strategy.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
1717
}
1818

1919
async validate(payload: any) {
20-
return { userId: payload.userID, username: payload.username };
20+
//return payload // for debugging purposes
21+
// cast userId to string in case it is a number
22+
// Backward compatibility for userId as number v3.0.0
23+
if (typeof payload.userId === 'number') {
24+
payload.userId = payload.userId.toString();
25+
}
26+
return { userId: payload.userId, username: payload.username };
2127
}
2228
}

server/src/database/database.service.ts

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,26 @@ import * as bcrypt from 'bcrypt';
66
@Injectable()
77
export class DatabaseService {
88

9-
private static readonly logger = new Logger(DatabaseService.name);
10-
private static readonly prisma = new PrismaClient();
9+
private logger = new Logger(DatabaseService.name);
10+
private readonly prisma = new PrismaClient();
1111

1212
constructor() {
1313
// Initialize the Prisma client
14-
DatabaseService.prisma.$connect()
14+
this.prisma.$connect()
1515
.then(() => {
16-
DatabaseService.logger.log('Connected to the database successfully.');
16+
this.logger.log('Connected to the database successfully.');
1717
})
1818
.catch((error) => {
19-
DatabaseService.logger.error('Failed to connect to the database.', error);
19+
this.logger.error('Failed to connect to the database.', error);
2020
});
2121
this.runMigrations()
2222
.then(() => {
2323
// create user after migrations
2424
this.createAdminUser()
25+
this.migrateLegeacyUsers()
2526
})
2627
.catch((error) => {
27-
DatabaseService.logger.error('Error during database migrations.', error);
28+
this.logger.error('Error during database migrations.', error);
2829
});
2930
}
3031

@@ -47,13 +48,13 @@ export class DatabaseService {
4748
const prisma = new PrismaClient();
4849

4950
try {
50-
Logger.log('Running Prisma migrations...', 'Bootstrap');
51+
this.logger.log('Running Prisma migrations...');
5152
// @ts-ignore
5253
await prisma.$executeRawUnsafe?.('PRAGMA foreign_keys=OFF;'); // For SQLite, optional
5354
// Use CLI for migrations
5455
execSync('npx prisma migrate deploy', { stdio: 'inherit' });
5556
//execSync('npx prisma migrate deploy', {});
56-
Logger.log('Prisma migrations completed.', 'Bootstrap');
57+
this.logger.log('Prisma migrations completed.');
5758
await prisma.$executeRaw`
5859
INSERT INTO "User" (
5960
"id",
@@ -74,7 +75,7 @@ export class DatabaseService {
7475
) ON CONFLICT DO NOTHING;`
7576
await prisma.$disconnect();
7677
} catch (err) {
77-
Logger.error('Prisma migration failed', err, 'Bootstrap');
78+
this.logger.error('Prisma migration failed', err);
7879
process.exit(1);
7980
}
8081
}
@@ -87,7 +88,7 @@ export class DatabaseService {
8788
where: { id: '2' },
8889
});
8990
if (existingUser) {
90-
Logger.log('Admin user already exists. Skipping creation.', 'DatabaseService');
91+
this.logger.log('Admin user already exists. Skipping creation.');
9192
return;
9293
}
9394

@@ -101,8 +102,6 @@ export class DatabaseService {
101102
// Erstelle einen bcrypt-Hash
102103
const passwordHash = await bcrypt.hash(plainPassword, 10);
103104
console.log('\n\n\n', 'Admin account created since no user exists yet');
104-
console.log('Please change the password after the first login.');
105-
console.log('Admin credentials:');
106105
console.log(' username: ', adminUser);
107106
console.log(' password: ', plainPassword);
108107
console.log(' email: ', adminEmail, '\n\n\n');
@@ -118,10 +117,70 @@ export class DatabaseService {
118117
updatedAt: new Date(),
119118
},
120119
});
121-
Logger.log('Admin user created successfully.', 'DatabaseService');
120+
this.logger.log('Admin user created successfully.');
122121
} catch (error) {
123-
Logger.error('Failed to create admin user.', error, 'DatabaseService');
122+
Logger.error('Failed to create admin user.', error);
124123
}
125-
await prisma.$disconnect();
124+
//await prisma.$disconnect();
125+
}
126+
127+
private async migrateLegeacyUsers() {
128+
const prisma = new PrismaClient();
129+
130+
const existingUsers = await prisma.user.count()
131+
if (existingUsers > 2) {
132+
this.logger.log('Legacy users already migrated. Skipping migration.');
133+
return;
134+
}
135+
136+
if (!process.env.KUBERO_USERS || process.env.KUBERO_USERS === '') {
137+
this.logger.log('No legacy users to migrate. KUBERO_USERS is not set.');
138+
return;
139+
}
140+
141+
const u = Buffer.from(process.env.KUBERO_USERS, 'base64').toString(
142+
'utf-8',
143+
);
144+
const users = JSON.parse(u);
145+
146+
for (const user of users) {
147+
let password = user.password;
148+
if (
149+
user.insecure &&
150+
user.insecure === true &&
151+
process.env.KUBERO_SESSION_KEY
152+
) {
153+
this.logger.warn(
154+
'User with unencrypted Password detected: "' +
155+
user.username +
156+
'" - This feature is deprecated and will be removed in the future',
157+
);
158+
password = crypto
159+
.createHmac('sha256', process.env.KUBERO_SESSION_KEY)
160+
.update(password)
161+
.digest('hex');
162+
}
163+
164+
const userID = crypto.randomUUID();
165+
166+
try {
167+
await prisma.user.create({
168+
data: {
169+
id: userID,
170+
username: user.username,
171+
email: user.username + '@kubero.dev',
172+
password: password,
173+
isActive: true,
174+
},
175+
});
176+
this.logger.log(`Migrated user ${user.username} successfully.`);
177+
178+
} catch (error) {
179+
this.logger.error(`Failed to migrate user ${user.username}.`, error);
180+
}
181+
};
182+
183+
this.logger.log('Legacy users migrated successfully.');
184+
//await prisma.$disconnect();
126185
}
127186
}

server/src/deployments/deployments.controller.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
Post,
88
Put,
99
UseGuards,
10+
Request,
1011
} from '@nestjs/common';
1112
import { DeploymentsService } from './deployments.service';
1213
import {
@@ -69,13 +70,12 @@ export class DeploymentsController {
6970
@Param('phase') phase: string,
7071
@Param('app') app: string,
7172
@Body() body: CreateBuild,
73+
@Request() req: any,
7274
) {
73-
//TODO: Migration -> this is a mock user
7475
const user: IUser = {
75-
id: 1,
76-
method: 'local',
77-
username: 'admin',
78-
apitoken: '1234567890',
76+
id: req.user.userId,
77+
strategy: req.user.strategy,
78+
username: req.user.username,
7979
};
8080
return this.deploymentsService.triggerBuildjob(
8181
pipeline,
@@ -108,13 +108,12 @@ export class DeploymentsController {
108108
@Param('phase') phase: string,
109109
@Param('app') app: string,
110110
@Param('buildName') buildName: string,
111+
@Request() req: any,
111112
) {
112-
//TODO: Migration -> this is a mock user
113113
const user: IUser = {
114-
id: 1,
115-
method: 'local',
116-
username: 'admin',
117-
apitoken: '1234567890',
114+
id: req.user.userId,
115+
strategy: req.user.strategy,
116+
username: req.user.username,
118117
};
119118
return this.deploymentsService.deleteBuildjob(
120119
pipeline,

0 commit comments

Comments
 (0)