diff --git a/apps/admin/backend/src/server.ts b/apps/admin/backend/src/server.ts index 98b01dc74..928bed82d 100644 --- a/apps/admin/backend/src/server.ts +++ b/apps/admin/backend/src/server.ts @@ -926,6 +926,7 @@ export async function start({ config: { allowElectionManagersToAccessUnconfiguredMachines: false, }, + logger, }), workspace: resolvedWorkspace, }); diff --git a/apps/central-scan/backend/src/server.ts b/apps/central-scan/backend/src/server.ts index 90fab9188..d7f5185ee 100644 --- a/apps/central-scan/backend/src/server.ts +++ b/apps/central-scan/backend/src/server.ts @@ -88,6 +88,7 @@ export async function start({ config: { allowElectionManagersToAccessUnconfiguredMachines: true, }, + logger, }), exporter: resolvedExporter, importer: resolvedImporter, diff --git a/apps/mark/backend/src/server.ts b/apps/mark/backend/src/server.ts index f946cec52..2bb932c18 100644 --- a/apps/mark/backend/src/server.ts +++ b/apps/mark/backend/src/server.ts @@ -28,6 +28,7 @@ export function start({ ], allowElectionManagersToAccessMachinesConfiguredForOtherElections: true, }, + logger, }); const app = buildApp(auth); diff --git a/apps/scan/backend/src/server.ts b/apps/scan/backend/src/server.ts index 9e52e72b4..f3cc73670 100644 --- a/apps/scan/backend/src/server.ts +++ b/apps/scan/backend/src/server.ts @@ -37,6 +37,7 @@ export function start({ 'poll_worker', ], }, + logger, }); const usb: Usb = { getUsbDrives }; const app = buildApp( diff --git a/libs/auth/src/dipped_smart_card_auth.test.ts b/libs/auth/src/dipped_smart_card_auth.test.ts index 9ae05e48f..6e0aef99c 100644 --- a/libs/auth/src/dipped_smart_card_auth.test.ts +++ b/libs/auth/src/dipped_smart_card_auth.test.ts @@ -1,3 +1,5 @@ +import { fakeLogger } from '@votingworks/logging'; + import { buildMockCard } from '../test/utils'; import { DippedSmartCardAuth } from './dipped_smart_card_auth'; @@ -7,7 +9,11 @@ beforeEach(() => { test('DippedSmartCardAuth returns auth status', async () => { const card = buildMockCard(); - const auth = new DippedSmartCardAuth({ card, config: {} }); + const auth = new DippedSmartCardAuth({ + card, + config: {}, + logger: fakeLogger(), + }); expect(await auth.getAuthStatus({ electionHash: undefined })).toEqual({ status: 'logged_out', reason: 'machine_locked', diff --git a/libs/auth/src/dipped_smart_card_auth.ts b/libs/auth/src/dipped_smart_card_auth.ts index a69e45d41..8986f31be 100644 --- a/libs/auth/src/dipped_smart_card_auth.ts +++ b/libs/auth/src/dipped_smart_card_auth.ts @@ -6,6 +6,11 @@ import { throwIllegalValue, wrapException, } from '@votingworks/basics'; +import { + LogDispositionStandardTypes, + LogEventId, + Logger, +} from '@votingworks/logging'; import { DippedSmartCardAuth as DippedSmartCardAuthTypes, User, @@ -48,12 +53,100 @@ function cardStatusToProgrammableCard( } } +/** + * Given a previous auth status and a new auth status following an auth status transition, infers + * and logs the relevant auth event, if any + */ +async function logAuthEventIfNecessary( + previousAuthStatus: DippedSmartCardAuthTypes.AuthStatus, + newAuthStatus: DippedSmartCardAuthTypes.AuthStatus, + logger: Logger +) { + switch (previousAuthStatus.status) { + case 'logged_out': { + if ( + previousAuthStatus.reason === 'machine_locked' && + newAuthStatus.status === 'logged_out' && + newAuthStatus.reason !== 'machine_locked' + ) { + await logger.log( + LogEventId.AuthLogin, + newAuthStatus.cardUserRole ?? 'unknown', + { + disposition: LogDispositionStandardTypes.Failure, + message: `User failed login: ${newAuthStatus.reason}.`, + reason: newAuthStatus.reason, + } + ); + } + return; + } + + case 'checking_pin': { + if (newAuthStatus.status === 'logged_out') { + await logger.log( + LogEventId.AuthPinEntry, + previousAuthStatus.user.role, + { + disposition: LogDispositionStandardTypes.Failure, + message: 'User canceled PIN entry.', + } + ); + } else if (newAuthStatus.status === 'remove_card') { + await logger.log(LogEventId.AuthPinEntry, newAuthStatus.user.role, { + disposition: LogDispositionStandardTypes.Success, + message: 'User entered correct PIN.', + }); + } else if (newAuthStatus.status === 'checking_pin') { + if ( + newAuthStatus.wrongPinEnteredAt && + newAuthStatus.wrongPinEnteredAt !== + previousAuthStatus.wrongPinEnteredAt + ) { + await logger.log( + LogEventId.AuthPinEntry, + previousAuthStatus.user.role, + { + disposition: LogDispositionStandardTypes.Failure, + message: 'User entered incorrect PIN.', + } + ); + } + } + return; + } + + case 'remove_card': { + if (newAuthStatus.status === 'logged_in') { + await logger.log(LogEventId.AuthLogin, newAuthStatus.user.role, { + disposition: LogDispositionStandardTypes.Success, + message: 'User logged in.', + }); + } + return; + } + + case 'logged_in': { + if (newAuthStatus.status === 'logged_out') { + await logger.log(LogEventId.AuthLogout, previousAuthStatus.user.role, { + disposition: LogDispositionStandardTypes.Success, + message: 'User logged out.', + }); + } + return; + } + + /* istanbul ignore next: Compile-time check for completeness */ + default: + throwIllegalValue(previousAuthStatus, 'status'); + } +} + /** * An implementation of the dipped smart card auth API * * TODO: * - Locking to avoid concurrent card writes - * - Logging * - Tests * * See the libs/auth README for notes on error handling @@ -62,11 +155,17 @@ export class DippedSmartCardAuth implements DippedSmartCardAuthApi { private authStatus: DippedSmartCardAuthTypes.AuthStatus; private readonly card: Card; private readonly config: DippedSmartCardAuthConfig; + private readonly logger: Logger; - constructor(input: { card: Card; config: DippedSmartCardAuthConfig }) { + constructor(input: { + card: Card; + config: DippedSmartCardAuthConfig; + logger: Logger; + }) { this.authStatus = DippedSmartCardAuthTypes.DEFAULT_AUTH_STATUS; this.card = input.card; this.config = input.config; + this.logger = input.logger; } async getAuthStatus( @@ -82,15 +181,14 @@ export class DippedSmartCardAuth implements DippedSmartCardAuthApi { ): Promise { await this.checkCardReaderAndUpdateAuthStatus(machineState); const checkPinResponse = await this.card.checkPin(input.pin); - this.updateAuthStatus(machineState, { + await this.updateAuthStatus(machineState, { type: 'check_pin', checkPinResponse, }); } async logOut(machineState: DippedSmartCardAuthMachineState): Promise { - this.updateAuthStatus(machineState, { type: 'log_out' }); - return Promise.resolve(); + await this.updateAuthStatus(machineState, { type: 'log_out' }); } async programCard( @@ -99,6 +197,68 @@ export class DippedSmartCardAuth implements DippedSmartCardAuthApi { | { userRole: 'system_administrator' } | { userRole: 'election_manager'; electionData: string } | { userRole: 'poll_worker' } + ): Promise> { + await this.logger.log( + LogEventId.SmartCardProgramInit, + 'system_administrator', + { + message: `Programming ${input.userRole} smart card...`, + programmedUserRole: input.userRole, + } + ); + const result = await this.programCardBase(machineState, input); + await this.logger.log( + LogEventId.SmartCardProgramComplete, + 'system_administrator', + { + disposition: result.isOk() ? 'success' : 'failure', + message: result.isOk() + ? `Successfully programmed ${input.userRole} smart card.` + : `Error programming ${input.userRole} smart card.`, + programmedUserRole: input.userRole, + } + ); + return result; + } + + async unprogramCard( + machineState: DippedSmartCardAuthMachineState + ): Promise> { + const programmedUserRole = + ('programmableCard' in this.authStatus && + 'programmedUser' in this.authStatus.programmableCard && + this.authStatus.programmableCard?.programmedUser?.role) ?? + 'unprogrammed'; + await this.logger.log( + LogEventId.SmartCardUnprogramInit, + 'system_administrator', + { + message: `Unprogramming ${programmedUserRole} smart card...`, + programmedUserRole, + } + ); + const result = await this.unprogramCardBase(machineState); + await this.logger.log( + LogEventId.SmartCardUnprogramComplete, + 'system_administrator', + { + disposition: result.isOk() ? 'success' : 'failure', + message: result.isOk() + ? `Successfully unprogrammed ${programmedUserRole} smart card.` + : `Error unprogramming ${programmedUserRole} smart card.`, + [result.isOk() ? 'previousProgrammedUserRole' : 'programmedUserRole']: + programmedUserRole, + } + ); + return result; + } + + private async programCardBase( + machineState: DippedSmartCardAuthMachineState, + input: + | { userRole: 'system_administrator' } + | { userRole: 'election_manager'; electionData: string } + | { userRole: 'poll_worker' } ): Promise> { await this.checkCardReaderAndUpdateAuthStatus(machineState); if (this.authStatus.status !== 'logged_in') { @@ -147,7 +307,7 @@ export class DippedSmartCardAuth implements DippedSmartCardAuthApi { return ok({ pin }); } - async unprogramCard( + private async unprogramCardBase( machineState: DippedSmartCardAuthMachineState ): Promise> { await this.checkCardReaderAndUpdateAuthStatus(machineState); @@ -170,17 +330,23 @@ export class DippedSmartCardAuth implements DippedSmartCardAuthApi { machineState: DippedSmartCardAuthMachineState ): Promise { const cardStatus = await this.card.getCardStatus(); - this.updateAuthStatus(machineState, { + await this.updateAuthStatus(machineState, { type: 'check_card_reader', cardStatus, }); } - private updateAuthStatus( + private async updateAuthStatus( machineState: DippedSmartCardAuthMachineState, action: AuthAction - ): void { + ): Promise { + const previousAuthStatus = this.authStatus; this.authStatus = this.determineNewAuthStatus(machineState, action); + await logAuthEventIfNecessary( + previousAuthStatus, + this.authStatus, + this.logger + ); } private determineNewAuthStatus( diff --git a/libs/auth/src/inserted_smart_card_auth.test.ts b/libs/auth/src/inserted_smart_card_auth.test.ts index 082fa2cff..606f10c6f 100644 --- a/libs/auth/src/inserted_smart_card_auth.test.ts +++ b/libs/auth/src/inserted_smart_card_auth.test.ts @@ -1,3 +1,5 @@ +import { fakeLogger } from '@votingworks/logging'; + import { buildMockCard } from '../test/utils'; import { InsertedSmartCardAuth } from './inserted_smart_card_auth'; @@ -9,6 +11,7 @@ test('InsertedSmartCardAuth returns auth status', async () => { const auth = new InsertedSmartCardAuth({ card: buildMockCard(), config: { allowedUserRoles: [] }, + logger: fakeLogger(), }); expect(await auth.getAuthStatus({ electionHash: undefined })).toEqual({ status: 'logged_out', diff --git a/libs/auth/src/inserted_smart_card_auth.ts b/libs/auth/src/inserted_smart_card_auth.ts index 5c37152e4..59a9c3a9f 100644 --- a/libs/auth/src/inserted_smart_card_auth.ts +++ b/libs/auth/src/inserted_smart_card_auth.ts @@ -8,6 +8,11 @@ import { throwIllegalValue, wrapException, } from '@votingworks/basics'; +import { + LogDispositionStandardTypes, + LogEventId, + Logger, +} from '@votingworks/logging'; import { BallotStyleId, CardlessVoterUser, @@ -33,12 +38,99 @@ type AuthAction = | { type: 'check_card_reader'; cardStatus: CardStatus } | { type: 'check_pin'; checkPinResponse: CheckPinResponse }; +/** + * Given a previous auth status and a new auth status following an auth status transition, infers + * and logs the relevant auth event, if any + */ +async function logAuthEvent( + previousAuthStatus: InsertedSmartCardAuthTypes.AuthStatus, + newAuthStatus: InsertedSmartCardAuthTypes.AuthStatus, + logger: Logger +) { + switch (previousAuthStatus.status) { + case 'logged_out': { + if (newAuthStatus.status === 'logged_in') { + await logger.log(LogEventId.AuthLogin, newAuthStatus.user.role, { + disposition: LogDispositionStandardTypes.Success, + message: 'User logged in.', + }); + } else if ( + previousAuthStatus.reason === 'no_card' && + newAuthStatus.status === 'logged_out' && + newAuthStatus.reason !== 'no_card' + ) { + await logger.log( + LogEventId.AuthLogin, + newAuthStatus.cardUserRole ?? 'unknown', + { + disposition: LogDispositionStandardTypes.Failure, + message: `User failed login: ${newAuthStatus.reason}.`, + reason: newAuthStatus.reason, + } + ); + } + return; + } + + case 'checking_pin': { + if (newAuthStatus.status === 'logged_out') { + await logger.log( + LogEventId.AuthPinEntry, + previousAuthStatus.user.role, + { + disposition: LogDispositionStandardTypes.Failure, + message: 'User canceled PIN entry.', + } + ); + } else if (newAuthStatus.status === 'logged_in') { + await logger.log(LogEventId.AuthPinEntry, newAuthStatus.user.role, { + disposition: LogDispositionStandardTypes.Success, + message: 'User entered correct PIN.', + }); + await logger.log(LogEventId.AuthLogin, newAuthStatus.user.role, { + disposition: LogDispositionStandardTypes.Success, + message: 'User logged in.', + }); + } else if (newAuthStatus.status === 'checking_pin') { + if ( + newAuthStatus.wrongPinEnteredAt && + previousAuthStatus.wrongPinEnteredAt !== + newAuthStatus.wrongPinEnteredAt + ) { + await logger.log( + LogEventId.AuthPinEntry, + previousAuthStatus.user.role, + { + disposition: LogDispositionStandardTypes.Failure, + message: 'User entered incorrect PIN.', + } + ); + } + } + return; + } + + case 'logged_in': { + if (newAuthStatus.status === 'logged_out') { + await logger.log(LogEventId.AuthLogout, previousAuthStatus.user.role, { + disposition: LogDispositionStandardTypes.Success, + message: 'User logged out.', + }); + } + return; + } + + /* istanbul ignore next: Compile-time check for completeness */ + default: + throwIllegalValue(previousAuthStatus, 'status'); + } +} + /** * An implementation of the dipped smart card auth API * * TODO: * - Locking to avoid concurrent card writes - * - Logging * - Tests * * See the libs/auth README for notes on error handling @@ -48,12 +140,18 @@ export class InsertedSmartCardAuth implements InsertedSmartCardAuthApi { private readonly card: Card; private cardlessVoterUser?: CardlessVoterUser; private readonly config: InsertedSmartCardAuthConfig; + private readonly logger: Logger; - constructor(input: { card: Card; config: InsertedSmartCardAuthConfig }) { + constructor(input: { + card: Card; + config: InsertedSmartCardAuthConfig; + logger: Logger; + }) { this.authStatus = InsertedSmartCardAuthTypes.DEFAULT_AUTH_STATUS; this.card = input.card; this.cardlessVoterUser = undefined; this.config = input.config; + this.logger = input.logger; } async getAuthStatus( @@ -94,7 +192,7 @@ export class InsertedSmartCardAuth implements InsertedSmartCardAuthApi { ): Promise { await this.checkCardReaderAndUpdateAuthStatus(machineState); const checkPinResponse = await this.card.checkPin(input.pin); - this.updateAuthStatus(machineState, { + await this.updateAuthStatus(machineState, { type: 'check_pin', checkPinResponse, }); @@ -105,7 +203,6 @@ export class InsertedSmartCardAuth implements InsertedSmartCardAuthApi { input: { ballotStyleId: BallotStyleId; precinctId: PrecinctId } ): Promise { assert(this.config.allowedUserRoles.includes('cardless_voter')); - await this.checkCardReaderAndUpdateAuthStatus(machineState); if ( this.authStatus.status !== 'logged_in' || @@ -115,13 +212,22 @@ export class InsertedSmartCardAuth implements InsertedSmartCardAuthApi { } this.cardlessVoterUser = { ...input, role: 'cardless_voter' }; + + await this.logger.log(LogEventId.AuthLogin, 'cardless_voter', { + disposition: LogDispositionStandardTypes.Success, + message: 'Cardless voter session started.', + }); } async endCardlessVoterSession(): Promise { assert(this.config.allowedUserRoles.includes('cardless_voter')); this.cardlessVoterUser = undefined; - return Promise.resolve(); + + await this.logger.log(LogEventId.AuthLogout, 'cardless_voter', { + disposition: LogDispositionStandardTypes.Success, + message: 'Cardless voter session ended.', + }); } async readCardData( @@ -184,17 +290,19 @@ export class InsertedSmartCardAuth implements InsertedSmartCardAuthApi { machineState: InsertedSmartCardAuthMachineState ): Promise { const cardStatus = await this.card.getCardStatus(); - this.updateAuthStatus(machineState, { + await this.updateAuthStatus(machineState, { type: 'check_card_reader', cardStatus, }); } - private updateAuthStatus( + private async updateAuthStatus( machineState: InsertedSmartCardAuthMachineState, action: AuthAction - ): void { + ): Promise { + const previousAuthStatus = this.authStatus; this.authStatus = this.determineNewAuthStatus(machineState, action); + await logAuthEvent(previousAuthStatus, this.authStatus, this.logger); } private determineNewAuthStatus( diff --git a/libs/logging/VotingWorksLoggingDocumentation.md b/libs/logging/VotingWorksLoggingDocumentation.md index af7a21ad5..090ec046e 100644 --- a/libs/logging/VotingWorksLoggingDocumentation.md +++ b/libs/logging/VotingWorksLoggingDocumentation.md @@ -46,14 +46,14 @@ IDs are logged with each log to identify the log being written. **Type:** [user-action](#user-action) **Description:** A user attempted to enter a PIN to log in. **Machines:** All -### auth-logout -**Type:** [user-action](#user-action) -**Description:** A user logged out. -**Machines:** All ### auth-login **Type:** [user-action](#user-action) **Description:** A user attempted to log in. Disposition is success if they logged in, failure if not. An optional reason may be provided. **Machines:** All +### auth-logout +**Type:** [user-action](#user-action) +**Description:** A user logged out. +**Machines:** All ### usb-drive-detected **Type:** [application-status](#application-status) **Description:** A USB drive was detected. @@ -138,26 +138,22 @@ IDs are logged with each log to identify the log being written. **Type:** [user-action](#user-action) **Description:** Report of all printed ballots was printed. Success or failure indicated by the disposition. **Machines:** vx-admin-frontend -### smartcard-program-init +### smart-card-program-init **Type:** [user-action](#user-action) -**Description:** A smartcard is being programmed for a specific user role. The user role is indicated by the programmedUserRole key. -**Machines:** vx-admin-frontend -### smartcard-program-complete +**Description:** A smart card is being programmed. The new smart card user role is indicated by the programmedUserRole key. +**Machines:** vx-admin-service +### smart-card-program-complete **Type:** [user-action](#user-action) -**Description:** A smartcard has been programmed for a specific user role. The user role is indicated by the programmedUserRole key. Success or failure is indicated by the disposition. -**Machines:** vx-admin-frontend -### smartcard-unprogram-init +**Description:** A smart card has been programmed. The new smart card user role is indicated by the programmedUserRole key. Success or failure is indicated by the disposition. +**Machines:** vx-admin-service +### smart-card-unprogram-init **Type:** [user-action](#user-action) -**Description:** A smartcard is being unprogrammed. The current smartcard user role is indicated by the programmedUserRole key. -**Machines:** vx-admin-frontend -### smartcard-unprogram-complete +**Description:** A smart card is being unprogrammed. The current smart card user role is indicated by the programmedUserRole key. +**Machines:** vx-admin-service +### smart-card-unprogram-complete **Type:** [user-action](#user-action) -**Description:** A smartcard has been unprogrammed. The previous (or current in the case of failure) smartcard user role is indicated by the previousProgrammedUserRole (or programmedUserRole in the case of failure) key. Success or failure is indicated by the disposition. -**Machines:** vx-admin-frontend -### smartcard-programmed-override-write-protection -**Type:** [user-action](#user-action) -**Description:** Smartcard is programmed to override a flag protecting writes on the card. By default admin cards can not be written unless write protection is first overridden. -**Machines:** vx-admin-frontend +**Description:** A smart card has been unprogrammed. The previous (or current in the case of failure) smart card user role is indicated by the previousProgrammedUserRole (or programmedUserRole in the case of failure) key. Success or failure is indicated by the disposition. +**Machines:** vx-admin-service ### cvr-loaded **Type:** [user-action](#user-action) **Description:** User loaded CVR to the machine. Success or failure indicated by disposition. diff --git a/libs/logging/src/log_documentation.test.ts b/libs/logging/src/log_documentation.test.ts index 9a6084e14..5b12c178c 100644 --- a/libs/logging/src/log_documentation.test.ts +++ b/libs/logging/src/log_documentation.test.ts @@ -27,7 +27,7 @@ describe('test cdf documentation generation', () => { expect(structuredData.DeviceModel).toEqual('VxAdmin 1.0'); expect(structuredData.GeneratedDate).toEqual('2020-07-24T00:00:00.000Z'); expect(structuredData.EventTypeDescription).toHaveLength(5); - expect(structuredData.EventIdDescription).toHaveLength(58); + expect(structuredData.EventIdDescription).toHaveLength(53); // Make sure VxAdminFrontend specific logs are included. expect(structuredData.EventIdDescription).toContainEqual( expect.objectContaining({ diff --git a/libs/logging/src/log_event_ids.ts b/libs/logging/src/log_event_ids.ts index ff389082d..22c2327ed 100644 --- a/libs/logging/src/log_event_ids.ts +++ b/libs/logging/src/log_event_ids.ts @@ -20,10 +20,10 @@ export enum LogEventId { MachineShutdownInit = 'machine-shutdown-init', MachineShutdownComplete = 'machine-shutdown-complete', UsbDeviceChangeDetected = 'usb-device-change-detected', - // Authentication related logs + // Auth logs AuthPinEntry = 'auth-pin-entry', - AuthLogout = 'auth-logout', AuthLogin = 'auth-login', + AuthLogout = 'auth-logout', // USB related logs UsbDriveDetected = 'usb-drive-detected', UsbDriveRemoved = 'usb-drive-removed', @@ -50,13 +50,10 @@ export enum LogEventId { SaveBallotPackageComplete = 'save-ballot-package-complete', BallotPrinted = 'ballot-printed', PrintedBallotReportPrinted = 'printed-ballot-report-printed', - SmartcardProgramInit = 'smartcard-program-init', - SmartcardProgramComplete = 'smartcard-program-complete', - SmartcardUnprogramInit = 'smartcard-unprogram-init', - SmartcardUnprogramComplete = 'smartcard-unprogram-complete', - // TODO(https://github.com/votingworks/vxsuite/issues/2085): - // Remove SmartcardProgrammedOverrideWriteProtection when removing legacy smartcards screen - SmartcardProgrammedOverrideWriteProtection = 'smartcard-programmed-override-write-protection', + SmartCardProgramInit = 'smart-card-program-init', + SmartCardProgramComplete = 'smart-card-program-complete', + SmartCardUnprogramInit = 'smart-card-unprogram-init', + SmartCardUnprogramComplete = 'smart-card-unprogram-complete', CvrLoaded = 'cvr-loaded', CvrFilesReadFromUsb = 'cvr-files-read-from-usb', RecomputingTally = 'recompute-tally-init', @@ -349,40 +346,33 @@ const FileSaved: LogDetails = { 'File is saved to a USB drive. Success or failure indicated by disposition. Type of file specified with "fileType" key. For success logs the saved filename specified with "filename" key.', }; -const SmartcardProgramInit: LogDetails = { - eventId: LogEventId.SmartcardProgramInit, - eventType: LogEventType.UserAction, - documentationMessage: - 'A smartcard is being programmed for a specific user role. The user role is indicated by the programmedUserRole key.', - restrictInDocumentationToApps: [LogSource.VxAdminFrontend], -}; -const SmartcardProgramComplete: LogDetails = { - eventId: LogEventId.SmartcardProgramComplete, +const SmartCardProgramInit: LogDetails = { + eventId: LogEventId.SmartCardProgramInit, eventType: LogEventType.UserAction, documentationMessage: - 'A smartcard has been programmed for a specific user role. The user role is indicated by the programmedUserRole key. Success or failure is indicated by the disposition.', - restrictInDocumentationToApps: [LogSource.VxAdminFrontend], + 'A smart card is being programmed. The new smart card user role is indicated by the programmedUserRole key.', + restrictInDocumentationToApps: [LogSource.VxAdminService], }; -const SmartcardUnprogramInit: LogDetails = { - eventId: LogEventId.SmartcardUnprogramInit, +const SmartCardProgramComplete: LogDetails = { + eventId: LogEventId.SmartCardProgramComplete, eventType: LogEventType.UserAction, documentationMessage: - 'A smartcard is being unprogrammed. The current smartcard user role is indicated by the programmedUserRole key.', - restrictInDocumentationToApps: [LogSource.VxAdminFrontend], + 'A smart card has been programmed. The new smart card user role is indicated by the programmedUserRole key. Success or failure is indicated by the disposition.', + restrictInDocumentationToApps: [LogSource.VxAdminService], }; -const SmartcardUnprogramComplete: LogDetails = { - eventId: LogEventId.SmartcardUnprogramComplete, +const SmartCardUnprogramInit: LogDetails = { + eventId: LogEventId.SmartCardUnprogramInit, eventType: LogEventType.UserAction, documentationMessage: - 'A smartcard has been unprogrammed. The previous (or current in the case of failure) smartcard user role is indicated by the previousProgrammedUserRole (or programmedUserRole in the case of failure) key. Success or failure is indicated by the disposition.', - restrictInDocumentationToApps: [LogSource.VxAdminFrontend], + 'A smart card is being unprogrammed. The current smart card user role is indicated by the programmedUserRole key.', + restrictInDocumentationToApps: [LogSource.VxAdminService], }; -const SmartcardProgrammedOverrideWriteProtection: LogDetails = { - eventId: LogEventId.SmartcardProgrammedOverrideWriteProtection, +const SmartCardUnprogramComplete: LogDetails = { + eventId: LogEventId.SmartCardUnprogramComplete, eventType: LogEventType.UserAction, documentationMessage: - 'Smartcard is programmed to override a flag protecting writes on the card. By default admin cards can not be written unless write protection is first overridden.', - restrictInDocumentationToApps: [LogSource.VxAdminFrontend], + 'A smart card has been unprogrammed. The previous (or current in the case of failure) smart card user role is indicated by the previousProgrammedUserRole (or programmedUserRole in the case of failure) key. Success or failure is indicated by the disposition.', + restrictInDocumentationToApps: [LogSource.VxAdminService], }; const CvrLoaded: LogDetails = { eventId: LogEventId.CvrLoaded, @@ -931,16 +921,14 @@ export function getDetailsForEventId(eventId: LogEventId): LogDetails { return PrintedBallotReportPrinted; case LogEventId.FileSaved: return FileSaved; - case LogEventId.SmartcardProgramInit: - return SmartcardProgramInit; - case LogEventId.SmartcardProgramComplete: - return SmartcardProgramComplete; - case LogEventId.SmartcardUnprogramInit: - return SmartcardUnprogramInit; - case LogEventId.SmartcardUnprogramComplete: - return SmartcardUnprogramComplete; - case LogEventId.SmartcardProgrammedOverrideWriteProtection: - return SmartcardProgrammedOverrideWriteProtection; + case LogEventId.SmartCardProgramInit: + return SmartCardProgramInit; + case LogEventId.SmartCardProgramComplete: + return SmartCardProgramComplete; + case LogEventId.SmartCardUnprogramInit: + return SmartCardUnprogramInit; + case LogEventId.SmartCardUnprogramComplete: + return SmartCardUnprogramComplete; case LogEventId.CvrFilesReadFromUsb: return CvrFilesReadFromUsb; case LogEventId.CvrLoaded: