sync-workshop-member-roster.mjs 1.9 KB

123456789101112131415161718192021222324
  1. /** Build a public classroom roster from an actual successful account audit, never from passwords. */
  2. import fs from 'node:fs/promises';
  3. import crypto from 'node:crypto';
  4. const auditFile = process.argv[2] || 'docs/board-login-20261111/account-verification.json';
  5. const audit = JSON.parse(await fs.readFile(auditFile, 'utf8'));
  6. if (audit.appId !== 'ncloudmaster' || audit.expectedCompanyObjectId !== 'FKieRbIoGt'
  7. || !Array.isArray(audit.results) || !audit.results.length || audit.total !== audit.results.length
  8. || audit.platformPassed !== audit.total || !Number.isFinite(Date.parse(audit.checkedAt))) throw Error('ROSTER_AUDIT_INVALID');
  9. const ids = new Set(), usernames = new Set();
  10. const members = audit.results.map(row => {
  11. if (!row.loginOk || !row.companyMatched || !row.profileNameMatched || !row.probeSessionClosed
  12. || typeof row.name !== 'string' || !row.name.trim() || typeof row.username !== 'string' || !row.username.trim()
  13. || typeof row.userId !== 'string' || !row.userId || ids.has(row.userId) || usernames.has(row.username)) throw Error('ROSTER_ACCOUNT_NOT_VERIFIED');
  14. ids.add(row.userId);usernames.add(row.username);
  15. return { id: 'platform-account:' + crypto.createHash('sha256').update(JSON.stringify(['ncloudmaster','FKieRbIoGt',row.userId])).digest('hex'),
  16. name: row.name.trim(), username: row.username.trim() };
  17. });
  18. const roster = { schema: 'ksf.workshop-members.v1', companyId: 'FKieRbIoGt', platformAppId: audit.appId,
  19. verifiedAt: audit.checkedAt, members };
  20. const body = '/** Verified public classroom roster. Regenerate with scripts/sync-workshop-member-roster.mjs after an account audit. */\n'
  21. + 'export const WORKSHOP_ROSTER = Object.freeze(' + JSON.stringify(roster, null, 2) + ');\n';
  22. await fs.writeFile('src/core/workshop-roster.js', body);
  23. console.log(JSON.stringify({ members: members.length, verifiedAt: roster.verifiedAt, file: 'src/core/workshop-roster.js', credentialValuesIncluded: false }));