diff options
author | Kristóf Marussy <kristof@marussy.com> | 2022-04-22 00:53:48 +0200 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2022-05-16 00:55:02 +0200 |
commit | 1184eb13f0bbe4768bf3dbd6cd31adf10c6c8dfe (patch) | |
tree | 78e6c699d8a232c948b40f643299f7af95a29215 /packages/main/src/stores | |
parent | feat(renderer): Insecure connection warning (diff) | |
download | sophie-1184eb13f0bbe4768bf3dbd6cd31adf10c6c8dfe.tar.gz sophie-1184eb13f0bbe4768bf3dbd6cd31adf10c6c8dfe.tar.zst sophie-1184eb13f0bbe4768bf3dbd6cd31adf10c6c8dfe.zip |
feat: Certificate viewer
Show certificates with an interface modeled after firefox's certificate
viewer so that they can be inspected before trusting.
The current implementation assumes that each certificate has a unique
fingerprint (collisions are astronomically unlikely).
Signed-off-by: Kristóf Marussy <kristof@marussy.com>
Diffstat (limited to 'packages/main/src/stores')
-rw-r--r-- | packages/main/src/stores/MainEnv.ts | 2 | ||||
-rw-r--r-- | packages/main/src/stores/Service.ts | 41 |
2 files changed, 40 insertions, 3 deletions
diff --git a/packages/main/src/stores/MainEnv.ts b/packages/main/src/stores/MainEnv.ts index 8923322..f9dc209 100644 --- a/packages/main/src/stores/MainEnv.ts +++ b/packages/main/src/stores/MainEnv.ts | |||
@@ -28,4 +28,6 @@ export default interface MainEnv { | |||
28 | openURLInExternalBrowser(url: string): void; | 28 | openURLInExternalBrowser(url: string): void; |
29 | 29 | ||
30 | openAboutDialog(): void; | 30 | openAboutDialog(): void; |
31 | |||
32 | saveTextFile(filename: string, value: string): Promise<void>; | ||
31 | } | 33 | } |
diff --git a/packages/main/src/stores/Service.ts b/packages/main/src/stores/Service.ts index d8f3166..1d46dc9 100644 --- a/packages/main/src/stores/Service.ts +++ b/packages/main/src/stores/Service.ts | |||
@@ -20,12 +20,13 @@ | |||
20 | 20 | ||
21 | import type { UnreadCount } from '@sophie/service-shared'; | 21 | import type { UnreadCount } from '@sophie/service-shared'; |
22 | import { | 22 | import { |
23 | CertificateSnapshotIn, | 23 | type Certificate, |
24 | type CertificateSnapshotIn, | ||
24 | defineServiceModel, | 25 | defineServiceModel, |
25 | ServiceAction, | 26 | ServiceAction, |
26 | ServiceStateSnapshotIn, | 27 | type ServiceStateSnapshotIn, |
27 | } from '@sophie/shared'; | 28 | } from '@sophie/shared'; |
28 | import { Instance, getSnapshot, cast } from 'mobx-state-tree'; | 29 | import { type Instance, getSnapshot, cast, flow } from 'mobx-state-tree'; |
29 | 30 | ||
30 | import type { ServiceView } from '../infrastructure/electron/types'; | 31 | import type { ServiceView } from '../infrastructure/electron/types'; |
31 | import { getLogger } from '../utils/log'; | 32 | import { getLogger } from '../utils/log'; |
@@ -129,6 +130,35 @@ const Service = defineServiceModel(ServiceSettings) | |||
129 | toggleDeveloperTools(): void { | 130 | toggleDeveloperTools(): void { |
130 | self.serviceView?.toggleDeveloperTools(); | 131 | self.serviceView?.toggleDeveloperTools(); |
131 | }, | 132 | }, |
133 | downloadCertificate: flow(function* downloadCertificate( | ||
134 | fingerprint: string, | ||
135 | ) { | ||
136 | const { state } = self; | ||
137 | if (state.type !== 'certificateError') { | ||
138 | log.warn( | ||
139 | 'Tried to save certificate', | ||
140 | fingerprint, | ||
141 | 'when there is no certificate error', | ||
142 | ); | ||
143 | return; | ||
144 | } | ||
145 | let { certificate } = state; | ||
146 | while ( | ||
147 | certificate !== undefined && | ||
148 | certificate.fingerprint !== fingerprint | ||
149 | ) { | ||
150 | certificate = certificate.issuerCert as Certificate; | ||
151 | } | ||
152 | if (certificate === undefined) { | ||
153 | log.warn( | ||
154 | 'Tried to save certificate', | ||
155 | fingerprint, | ||
156 | 'which is not part of the current certificate chain', | ||
157 | ); | ||
158 | return; | ||
159 | } | ||
160 | yield getEnv(self).saveTextFile('certificate.pem', certificate.data); | ||
161 | }), | ||
132 | })) | 162 | })) |
133 | .actions((self) => { | 163 | .actions((self) => { |
134 | function setState(state: ServiceStateSnapshotIn): void { | 164 | function setState(state: ServiceStateSnapshotIn): void { |
@@ -272,6 +302,11 @@ const Service = defineServiceModel(ServiceSettings) | |||
272 | case 'dismiss-all-popups': | 302 | case 'dismiss-all-popups': |
273 | self.dismissAllPopups(); | 303 | self.dismissAllPopups(); |
274 | break; | 304 | break; |
305 | case 'download-certificate': | ||
306 | self.downloadCertificate(action.fingerprint).catch((error) => { | ||
307 | log.error('Error while saving certificate', error); | ||
308 | }); | ||
309 | break; | ||
275 | default: | 310 | default: |
276 | log.error('Unknown action to dispatch', action); | 311 | log.error('Unknown action to dispatch', action); |
277 | break; | 312 | break; |