import { Rule } from "../rule"; import { Context } from "../context"; import { Options } from "../options"; import { Client } from "../client"; import { ADGroup } from "azure-graph/lib/models"; import { isUUID, getEmail } from "../utils"; export default class GroupMembers extends Rule { private readonly group: string[]; private readonly members: string[]; constructor(context: Context, options: Options) { super(context, options); this.group = options.stringList("group"); this.members = options.stringList("members"); } async run(client: Client): Promise { function same(a?: string | null, b?: string | null): boolean { return a != null && b != null && a.toLowerCase() === b.toLowerCase(); } for (const name of this.group) { const group = await this.getGroup(client, name); const users = await client.listGroupMembers(group.objectId!!); const existing = users.map(getEmail); const missing = this.members.filter( member => !existing.some(e => same(e, member)) ); if (missing.length > 0) { this.report(group, "missingGroupMembers", { name: group.displayName, missing: missing.join(", ") }); } const invalid = existing.filter( e => !this.members.some(member => same(e, member)) ); if (invalid.length > 0) { this.report(group, "invalidGroupMembers", { name: group.displayName, invalid: invalid.join(", ") }); } } } async getGroup(client: Client, name: string): Promise { if (isUUID(name)) { return client.getGroup(name); } else { const groups = await client.listGroups(); const filtered = groups.filter(g => g.displayName === name); if (filtered.length === 0) { throw new Error("Group not found: " + name); } else if (filtered.length === 1) { return filtered[0]; } else { throw new Error("More than one matching group found: " + name); } } } }