1
0
mirror of https://github.com/stonith404/pingvin-share.git synced 2024-11-15 11:50:34 +01:00

refactor: run formatter

This commit is contained in:
Elias Schneider 2024-09-03 22:54:53 +02:00
parent e813da05ae
commit 3d2b978daf
No known key found for this signature in database
GPG Key ID: 07E623B294202B6C
7 changed files with 194 additions and 142 deletions

View File

@ -20,4 +20,4 @@ import { UserModule } from "../user/user.module";
providers: [AuthService, AuthTotpService, JwtStrategy, LdapService], providers: [AuthService, AuthTotpService, JwtStrategy, LdapService],
exports: [AuthService], exports: [AuthService],
}) })
export class AuthModule { } export class AuthModule {}

View File

@ -29,7 +29,7 @@ export class AuthService {
private emailService: EmailService, private emailService: EmailService,
private ldapService: LdapService, private ldapService: LdapService,
private userService: UserSevice, private userService: UserSevice,
) { } ) {}
private readonly logger = new Logger(AuthService.name); private readonly logger = new Logger(AuthService.name);
async signUp(dto: AuthRegisterDTO, ip: string, isAdmin?: boolean) { async signUp(dto: AuthRegisterDTO, ip: string, isAdmin?: boolean) {
@ -76,18 +76,28 @@ export class AuthService {
}, },
}); });
if (user?.password && await argon.verify(user.password, dto.password)) { if (user?.password && (await argon.verify(user.password, dto.password))) {
this.logger.log(`Successful password login for user ${user.email} from IP ${ip}`); this.logger.log(
`Successful password login for user ${user.email} from IP ${ip}`,
);
return this.generateToken(user); return this.generateToken(user);
} }
} }
if (this.config.get("ldap.enabled")) { if (this.config.get("ldap.enabled")) {
this.logger.debug(`Trying LDAP login for user ${dto.username}`); this.logger.debug(`Trying LDAP login for user ${dto.username}`);
const ldapUser = await this.ldapService.authenticateUser(dto.username, dto.password); const ldapUser = await this.ldapService.authenticateUser(
dto.username,
dto.password,
);
if (ldapUser) { if (ldapUser) {
const user = await this.userService.findOrCreateFromLDAP(dto.username, ldapUser); const user = await this.userService.findOrCreateFromLDAP(
this.logger.log(`Successful LDAP login for user ${user.email} from IP ${ip}`); dto.username,
ldapUser,
);
this.logger.log(
`Successful LDAP login for user ${user.email} from IP ${ip}`,
);
return this.generateToken(user); return this.generateToken(user);
} }
} }

View File

@ -1,16 +1,26 @@
import { Inject, Injectable, Logger } from "@nestjs/common"; import { Inject, Injectable, Logger } from "@nestjs/common";
import * as ldap from "ldapjs"; import * as ldap from "ldapjs";
import { AttributeJson, InvalidCredentialsError, SearchCallbackResponse, SearchOptions } from "ldapjs"; import {
AttributeJson,
InvalidCredentialsError,
SearchCallbackResponse,
SearchOptions,
} from "ldapjs";
import { inspect } from "node:util"; import { inspect } from "node:util";
import { ConfigService } from "../config/config.service"; import { ConfigService } from "../config/config.service";
type LdapSearchEntry = { type LdapSearchEntry = {
objectName: string, objectName: string;
attributes: AttributeJson[], attributes: AttributeJson[];
}; };
async function ldapExecuteSearch(client: ldap.Client, base: string, options: SearchOptions): Promise<LdapSearchEntry[]> { async function ldapExecuteSearch(
const searchResponse = await new Promise<SearchCallbackResponse>((resolve, reject) => { client: ldap.Client,
base: string,
options: SearchOptions,
): Promise<LdapSearchEntry[]> {
const searchResponse = await new Promise<SearchCallbackResponse>(
(resolve, reject) => {
client.search(base, options, (err, res) => { client.search(base, options, (err, res) => {
if (err) { if (err) {
reject(err); reject(err);
@ -18,45 +28,62 @@ async function ldapExecuteSearch(client: ldap.Client, base: string, options: Sea
resolve(res); resolve(res);
} }
}); });
}); },
);
return await new Promise<any[]>((resolve, reject) => { return await new Promise<any[]>((resolve, reject) => {
const entries: LdapSearchEntry[] = []; const entries: LdapSearchEntry[] = [];
searchResponse.on("searchEntry", entry => entries.push({ attributes: entry.pojo.attributes, objectName: entry.pojo.objectName })); searchResponse.on("searchEntry", (entry) =>
entries.push({
attributes: entry.pojo.attributes,
objectName: entry.pojo.objectName,
}),
);
searchResponse.once("error", reject); searchResponse.once("error", reject);
searchResponse.once("end", () => resolve(entries)); searchResponse.once("end", () => resolve(entries));
}); });
} }
async function ldapBindUser(client: ldap.Client, dn: string, password: string): Promise<void> { async function ldapBindUser(
client: ldap.Client,
dn: string,
password: string,
): Promise<void> {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
client.bind(dn, password, error => { client.bind(dn, password, (error) => {
if (error) { if (error) {
reject(error); reject(error);
} else { } else {
resolve(); resolve();
} }
}); });
}) });
} }
async function ldapCreateConnection(logger: Logger, url: string): Promise<ldap.Client> { async function ldapCreateConnection(
logger: Logger,
url: string,
): Promise<ldap.Client> {
const ldapClient = ldap.createClient({ const ldapClient = ldap.createClient({
url: url.split(","), url: url.split(","),
connectTimeout: 10_000, connectTimeout: 10_000,
timeout: 10_000 timeout: 10_000,
}); });
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
ldapClient.once("error", reject); ldapClient.once("error", reject);
ldapClient.on("setupError", reject); ldapClient.on("setupError", reject);
ldapClient.on("socketTimeout", reject); ldapClient.on("socketTimeout", reject);
ldapClient.on("connectRefused", () => reject(new Error("connection has been refused"))); ldapClient.on("connectRefused", () =>
ldapClient.on("connectTimeout", () => reject(new Error("connect timed out"))); reject(new Error("connection has been refused")),
);
ldapClient.on("connectTimeout", () =>
reject(new Error("connect timed out")),
);
ldapClient.on("connectError", reject); ldapClient.on("connectError", reject);
ldapClient.on("connect", resolve); ldapClient.on("connect", resolve);
}).catch(error => { }).catch((error) => {
logger.error(`Connect error: ${inspect(error)}`); logger.error(`Connect error: ${inspect(error)}`);
ldapClient.destroy(); ldapClient.destroy();
throw error; throw error;
@ -66,8 +93,8 @@ async function ldapCreateConnection(logger: Logger, url: string): Promise<ldap.C
} }
export type LdapAuthenticateResult = { export type LdapAuthenticateResult = {
userDn: string, userDn: string;
attributes: Record<string, string[]> attributes: Record<string, string[]>;
}; };
@Injectable() @Injectable()
@ -76,7 +103,7 @@ export class LdapService {
constructor( constructor(
@Inject(ConfigService) @Inject(ConfigService)
private readonly serviceConfig: ConfigService, private readonly serviceConfig: ConfigService,
) { } ) {}
private async createLdapConnection(): Promise<ldap.Client> { private async createLdapConnection(): Promise<ldap.Client> {
const ldapUrl = this.serviceConfig.get("ldap.url"); const ldapUrl = this.serviceConfig.get("ldap.url");
@ -89,7 +116,11 @@ export class LdapService {
const bindDn = this.serviceConfig.get("ldap.bindDn") || null; const bindDn = this.serviceConfig.get("ldap.bindDn") || null;
if (bindDn) { if (bindDn) {
try { try {
await ldapBindUser(ldapClient, bindDn, this.serviceConfig.get("ldap.bindPassword")) await ldapBindUser(
ldapClient,
bindDn,
this.serviceConfig.get("ldap.bindPassword"),
);
} catch (error) { } catch (error) {
this.logger.warn(`Failed to bind to default user: ${error}`); this.logger.warn(`Failed to bind to default user: ${error}`);
throw new Error("failed to bind to default user"); throw new Error("failed to bind to default user");
@ -103,20 +134,24 @@ export class LdapService {
} }
} }
public async authenticateUser(username: string, password: string): Promise<LdapAuthenticateResult | null> { public async authenticateUser(
username: string,
password: string,
): Promise<LdapAuthenticateResult | null> {
if (!username.match(/^[a-zA-Z0-0]+$/)) { if (!username.match(/^[a-zA-Z0-0]+$/)) {
return null; return null;
} }
const searchBase = this.serviceConfig.get("ldap.searchBase"); const searchBase = this.serviceConfig.get("ldap.searchBase");
const searchQuery = this.serviceConfig.get("ldap.searchQuery") const searchQuery = this.serviceConfig
.get("ldap.searchQuery")
.replaceAll("%username%", username); .replaceAll("%username%", username);
const ldapClient = await this.createLdapConnection(); const ldapClient = await this.createLdapConnection();
try { try {
const [result] = await ldapExecuteSearch(ldapClient, searchBase, { const [result] = await ldapExecuteSearch(ldapClient, searchBase, {
filter: searchQuery, filter: searchQuery,
scope: "sub" scope: "sub",
}); });
if (!result) { if (!result) {
@ -134,7 +169,12 @@ export class LdapService {
*/ */
return { return {
userDn: result.objectName, userDn: result.objectName,
attributes: Object.fromEntries(result.attributes.map(attribute => [attribute.type, attribute.values])), attributes: Object.fromEntries(
result.attributes.map((attribute) => [
attribute.type,
attribute.values,
]),
),
}; };
} catch (error) { } catch (error) {
if (error instanceof InvalidCredentialsError) { if (error instanceof InvalidCredentialsError) {

View File

@ -34,7 +34,9 @@ export class UserDTO {
totpVerified: boolean; totpVerified: boolean;
from(partial: Partial<UserDTO>) { from(partial: Partial<UserDTO>) {
const result = plainToClass(UserDTO, partial, { excludeExtraneousValues: true }); const result = plainToClass(UserDTO, partial, {
excludeExtraneousValues: true,
});
result.isLdap = partial.ldapDN?.length > 0; result.isLdap = partial.ldapDN?.length > 0;
return result; return result;
} }

View File

@ -8,6 +8,6 @@ import { FileModule } from "src/file/file.module";
imports: [EmailModule, FileModule], imports: [EmailModule, FileModule],
providers: [UserSevice], providers: [UserSevice],
controllers: [UserController], controllers: [UserController],
exports: [UserSevice] exports: [UserSevice],
}) })
export class UserModule { } export class UserModule {}

View File

@ -17,7 +17,7 @@ export class UserSevice {
private emailService: EmailService, private emailService: EmailService,
private fileService: FileService, private fileService: FileService,
private configService: ConfigService, private configService: ConfigService,
) { } ) {}
async list() { async list() {
return await this.prisma.user.findMany(); return await this.prisma.user.findMany();
@ -94,7 +94,9 @@ export class UserSevice {
async findOrCreateFromLDAP(username: string, ldap: LdapAuthenticateResult) { async findOrCreateFromLDAP(username: string, ldap: LdapAuthenticateResult) {
const passwordHash = await argon.hash(crypto.randomUUID()); const passwordHash = await argon.hash(crypto.randomUUID());
const userEmail = ldap.attributes["userPrincipalName"]?.at(0) ?? `${crypto.randomUUID()}@ldap.local`; const userEmail =
ldap.attributes["userPrincipalName"]?.at(0) ??
`${crypto.randomUUID()}@ldap.local`;
const adminGroup = this.configService.get("ldap.adminGroups"); const adminGroup = this.configService.get("ldap.adminGroups");
const isAdmin = ldap.attributes["memberOf"]?.includes(adminGroup) ?? false; const isAdmin = ldap.attributes["memberOf"]?.includes(adminGroup) ?? false;
try { try {
@ -114,8 +116,8 @@ export class UserSevice {
ldapDN: ldap.userDn, ldapDN: ldap.userDn,
}, },
where: { where: {
ldapDN: ldap.userDn ldapDN: ldap.userDn,
} },
}); });
} catch (e) { } catch (e) {
if (e instanceof PrismaClientKnownRequestError) { if (e instanceof PrismaClientKnownRequestError) {

View File

@ -162,9 +162,7 @@ export default function Home() {
size="md" size="md"
className={classes.control} className={classes.control}
> >
<FormattedMessage <FormattedMessage id="home.button.start" />
id="home.button.start"
/>
</Button> </Button>
<Button <Button
component={Link} component={Link}