-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature: Certificate Enhancements #300
base: rc-1.6.0
Are you sure you want to change the base?
Conversation
…intain a unique hash for a cert in the DB to ensure that we can persist a matching unique record for each cert file that is uploaded into fileAccess feat: created InstallCertificateAttempt and DeleteCertificateAttempt repositories to help keep track of certs that are being installed / deleted so that the InstalledCertificates repository can be updated appropriately when successful responses from the charger are received feat: created UploadExistingCertificate endpoint to support being able to upload a certificate and tie it as an installed certificate on the charger, to be used during initial set up to upload certificates into COS that are already set up on the charger feat: created RegenerateExistingCertificate to generate a new certificate that is signed by old feat: adjusting InstallCertificate endpoint to get a certificate hash for the certificate that is being installed, and if a Certificate record does not yet exist for the provided certificate / hash, then a new record is created and the cert file is uploaded via fileAccess. The InstallCertificateAttempt record is created in pending state (status null) which will later be used to handle appropriately setting InstalledCertificate record feat: adjusted InstallCertificate handler to check for and update applicable pending InstallCertificateAttempt record and if the InstallCertificate status was successful, then InstalledCertificate record will be created / updated appropriately feat: adjusting GetGetInstalledCertificateIds handler to appropriately update InstalledCertificate records where previously we were deleting all and bulk inserting, now it will look for existing matches and update or insert new feat: adjusting DeleteCertificate handler to appropriately update InstalledCertificate records fix: CORS issue happening because OPTIONS was missing from list of supported methods
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Elliot, thanks for the effort! This code change is so big and complex. 👍 I think it would be better to test the related flows manually before merging if haven't.
@@ -73,6 +74,7 @@ import { TariffQueryString } from './queries/Tariff'; | |||
import { LocalListVersion } from '../layers/sequelize/model/Authorization/LocalListVersion'; | |||
import { SendLocalList } from '../layers/sequelize/model/Authorization/SendLocalList'; | |||
import { InstalledCertificate } from '../layers/sequelize/model/Certificate/InstalledCertificate'; | |||
import { InstallCertificateAttempt } from '../layers/sequelize/model/Certificate/InstallCertificateAttempt'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super minor: InstallCertificateAttempt
can be put together with DeleteCertificateAttempt
at line 55.
@@ -63,6 +63,9 @@ export class Certificate extends Model { | |||
@Column(DataType.STRING) | |||
declare certificateFileId?: string | null; | |||
|
|||
@Column(DataType.STRING) | |||
declare certificateFileHash?: string | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be unique?
station?: ChargingStation; | ||
|
||
@Column({ | ||
type: DataType.ENUM('SHA256', 'SHA384', 'SHA512'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about just using values from the enum? The same idea for enum columns in InstallCertificateAttempt
and InstalledCertificate
.
type: DataType.ENUM('SHA256', 'SHA384', 'SHA512'), | |
type: DataType.ENUM(...Object.values(HashAlgorithmEnumType)), |
}) | ||
declare status?: InstallCertificateStatusEnumType | null; | ||
|
||
declare customData?: CustomDataType | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be missed to remove?
@@ -15,31 +16,38 @@ export class InstalledCertificate extends Model implements CertificateHashDataTy | |||
|
|||
@Column({ | |||
type: DataType.STRING, | |||
allowNull: false, | |||
allowNull: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does these column changes from required to optional?
const [newCertificatePem, _newPrivateKeyPem] = generateCertificate( | ||
existingCertificateRecord, | ||
this._logger, | ||
undefined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to use a existing cert to sign a new one, the issuerKeyPem
is required. It should match the public key of the existingCertificate. We can find it by existingCertificateRecord.privateKeyFileId
and then use this._fileAccess.getFile()
to get the pem.
const existingCertificateBuffer = await this._fileAccess.getFile(fileId); | ||
const existingCertificate = existingCertificateBuffer.toString(); | ||
const [newCertificatePem, _newPrivateKeyPem] = generateCertificate( | ||
existingCertificateRecord, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we cannot use existingCertificateRecord
directly. The new certificate will be generate based on the value that is assigned to certificateEntity
of this generateCertificate()
method. For instance, we need a new validBefore
for new cert rather than the old one in existingCertificateRecord
. The issuer and subject are also different.
How about we move the part between line 682 and 702 before generateCertificate
and use that new certificate entity for the method?
const newCertificateHash = this.getCertificateHash(newCertificatePem); | ||
let newCertificateRecord = new Certificate(); | ||
newCertificateRecord.serialNumber = moment().valueOf(); | ||
newCertificateRecord.issuerName = existingCertificateRecord.issuerName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issuerName of the new cert should be the subjectName of the existing certificate.
existingCertificateRecord.organizationName; | ||
newCertificateRecord.commonName = existingCertificateRecord.commonName; | ||
newCertificateRecord.keyLength = existingCertificateRecord.keyLength; | ||
newCertificateRecord.validBefore = existingCertificateRecord.validBefore; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need a new date in validBefore
. The existing one might be outdated.
newCertificateRecord.countryName = existingCertificateRecord.countryName; | ||
newCertificateRecord.isCA = existingCertificateRecord.isCA; | ||
newCertificateRecord.pathLen = existingCertificateRecord.pathLen; | ||
newCertificateRecord.signedBy = existingCertificateRecord.signedBy; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
signedBy
would be existingCertificateRecord.id
Related PR: citrineos/citrineos-operator-ui#78