@nephele/authenticator-pam
Version:
PAM based authenticator (local system users) for the Nephele WebDAV server.
85 lines (72 loc) • 2.13 kB
text/typescript
import { createRequire } from 'node:module';
import userid from 'userid';
import type { User as UserInterface } from 'nephele';
import { ForbiddenError, UnauthorizedError } from 'nephele';
const require = createRequire(import.meta.url);
const pam = require('authenticate-pam');
const { ids, groupname, gids } = userid;
export default class User implements UserInterface {
username: string;
groupname?: string;
uid?: number;
gid?: number;
gids?: number[];
private authenticated = false;
constructor({ username }: { username: string }) {
this.username = username;
try {
const { uid, gid } = ids(username);
this.uid = uid;
this.gid = gid;
this.groupname = groupname(gid);
this.gids = gids(username);
} catch (e: any) {
if (e.message.includes('username not found')) {
this.uid = undefined;
this.gid = undefined;
this.groupname = undefined;
this.gids = undefined;
}
}
}
async authenticate(password: string, remoteHost: string = '127.0.0.1') {
if (this.authenticated) {
return;
}
return await new Promise<void>((resolve, reject) => {
pam.authenticate(
this.username,
password,
(err?: string) => {
if (err) {
reject(new UnauthorizedError(err));
} else {
this.authenticated = true;
resolve();
}
},
{ serviceName: 'login', remoteHost },
);
});
}
async checkUID(allowedUIDs: string[]) {
if (this.uid == null) {
throw new UnauthorizedError('Unknown user.');
}
for (let range of allowedUIDs) {
const parts = range.split('-');
if (parts.length < 1 || parts.length > 2) {
throw new Error('allowedUIDs settings is misconfigured!');
}
if (
(parts.length === 1 && this.uid === parseInt(parts[0])) ||
(parts.length === 2 &&
this.uid >= parseInt(parts[0]) &&
this.uid <= parseInt(parts[1]))
) {
return;
}
}
throw new ForbiddenError('You are not allowed to log in.');
}
}