@@ -16,7 +16,7 @@ import path from "path";
1616import * as schedule from "node-schedule" ;
1717import { getUserByCardTagID , getUsersFullName } from "./database/repositories/Users/UserRepository.js" ;
1818import { createUnassocaitedAuditLog } from "./database/repositories/AuditLogs/AuditLogRepository.js" ;
19- import { getReaderCertCA } from "./database/repositories/Readers/ReaderRepository.js" ;
19+ import { getReaderCertCA , setReaderCertCA } from "./database/repositories/Readers/ReaderRepository.js" ;
2020import morgan from "morgan" ; //Log provider
2121import { createRequire } from "module" ;
2222import { setDataPointValue } from "./database/repositories/DataPoints/DataPointsRepository.js" ;
@@ -43,10 +43,10 @@ import fs from "node:fs";
4343import { ViteDevServer } from "vite" ;
4444import { SiteSettings } from "./database/models/site_settings/SiteSettings.js" ;
4545import * as ThemeRepo from "./database/repositories/SiteSettings/ThemesRepository.js" ;
46+ import { createHash } from 'node:crypto' ;
4647
4748const require = createRequire ( import . meta. url ) ;
4849
49- const allowed_origins = [ process . env . VITE_ORIGIN , "https://studio.apollographql.com" , "https://make.rit.edu" , "https://shibboleth.main.ad.rit.edu" ] ;
5050const SECURE_ORIGIN = ( process . env . VITE_ORIGIN ?? "" ) ;
5151const __dirname = import . meta. dirname ;
5252
@@ -249,12 +249,32 @@ async function startServer() {
249249 } ) ;
250250 app . use ( "/api/files/" , express . static ( path . join ( __dirname , '../../client/shlug-files/' ) ) ) ;
251251
252- app . get ( "/api/files/certCA" , async function ( req , res ) {
252+ app . get ( "/api/rootCA" , async function ( req , res ) {
253+ const SNHeader = 'shlug-sn' ;
254+ if ( ! req . headers [ SNHeader ] ) {
255+ return res . status ( 401 ) . send ( ) ;
256+ }
257+ const SN = req . headers [ SNHeader ] ;
258+ if ( typeof SN !== "string" ) {
259+ return res . status ( 401 ) . send ( ) ;
260+ }
261+
262+ const device = await getDeviceBySN ( SN ) ;
263+ if ( device == null ) {
264+ return res . status ( 404 ) . send ( ) ;
265+ }
266+
253267 const certca = ( await getReaderCertCA ( ) ) ?. value ;
254268 if ( certca == null ) {
255269 return res . status ( 404 ) . send ( ) ;
256270 }
257- return res . send ( certca ) ;
271+ const textForSha = `${ device . SN } :${ await device . generateKey ( ) } :${ certca } `
272+ const sha = createHash ( 'sha256' ) . update ( textForSha ) . digest ( 'hex' )
273+ const result = {
274+ cert : certca ,
275+ sha : sha ,
276+ }
277+ return res . json ( result ) ;
258278 } )
259279
260280 app . get ( '/api/files/ota/:tagname' , async function ( req , res ) {
@@ -542,6 +562,27 @@ async function startServer() {
542562 createUnassocaitedAuditLog ( `Trainings: Sent ${ numNotified } expiry notices, and purged ${ numPurged } expired trainings.` , "server" )
543563
544564 }
565+ async function updateRootCert ( ) {
566+ try {
567+ const url = process . env . READER_CERT_URL ;
568+ if ( url == undefined || url == "" ) {
569+ console . error ( "Can not update root cert. No download URL provided" ) ;
570+ return
571+ }
572+ const response = await fetch ( url ) ;
573+
574+ if ( ! response . ok ) {
575+ console . error ( `Could not download new root cert. HTTP error: ${ response . status } ` )
576+ return ;
577+ }
578+
579+ const certString = await response . text ( ) ;
580+ // normalize \r\n to \n
581+ setReaderCertCA ( certString . replace ( / \r / g, "" ) ) ;
582+ } catch ( error ) {
583+ console . error ( `Failed to update root cert: ${ error } ` )
584+ }
585+ }
545586 /**
546587 Cron Format:
547588 * * * * * *
@@ -574,6 +615,9 @@ async function startServer() {
574615 // Advance any time-based maintennace tickets from UPCOMING -> TODO
575616 await advanceTimeTickets ( ) ;
576617
618+ // Get a new root certificate for readers
619+ await updateRootCert ( ) ;
620+
577621 // Command all cores to restart for the periodic restart
578622 await scheduledRestartAllCores ( ) ;
579623 } ) ;
0 commit comments