documentation-hub 5.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +43 -0
- package/.github/workflows/build.yml +64 -0
- package/.github/workflows/ci.yml +39 -0
- package/.vscode/extensions.json +3 -0
- package/Current.md +97 -0
- package/DocHub_Image.png +0 -0
- package/README.md +666 -0
- package/USER_GUIDE.md +1173 -0
- package/Updater.md +311 -0
- package/build/256x256.png +0 -0
- package/build/512x512.png +0 -0
- package/build/app-update.yml +4 -0
- package/build/create-icon.js +208 -0
- package/build/icon.ico +0 -0
- package/build/icon.png +0 -0
- package/build/icon_1024x1024.png +0 -0
- package/dist/assets/Analytics-BpsG9895.js +1 -0
- package/dist/assets/Card-IAZin8kp.js +1 -0
- package/dist/assets/CurrentSession-B-rFkHvf.js +12 -0
- package/dist/assets/Dashboard-C_5gMb0q.js +1 -0
- package/dist/assets/Documents-CqZ25axS.js +1 -0
- package/dist/assets/Input-l89xwXBi.js +1 -0
- package/dist/assets/Reporting-DqdHJY_a.js +1 -0
- package/dist/assets/Search-XNbu5z_3.js +1 -0
- package/dist/assets/SessionManager-lH9hZfzH.js +1 -0
- package/dist/assets/Sessions-ClZOPYNc.js +1 -0
- package/dist/assets/Settings-DUEHGURa.js +11 -0
- package/dist/assets/index-8xUe8ptc.js +24 -0
- package/dist/assets/index-RYyJqF7O.css +1 -0
- package/dist/assets/path-BkOl0AGO.js +1 -0
- package/dist/assets/promises-ID_B9S-h.js +1 -0
- package/dist/assets/urlHelpers-TvgahX0r.js +1 -0
- package/dist/assets/useToast-yRSO1dkm.js +1 -0
- package/dist/assets/vendor-charts-RkGK5ROP.js +36 -0
- package/dist/assets/vendor-db-l0sNRNKZ.js +1 -0
- package/dist/assets/vendor-react-BVZ_anCF.js +4 -0
- package/dist/assets/vendor-search-Dw8P0qyA.js +1 -0
- package/dist/assets/vendor-ui-BU7NfluV.js +53 -0
- package/dist/electron/PowerAutomateApiService-LfW09ZGr.js +147 -0
- package/dist/electron/main-CXkNtyv-.js +19789 -0
- package/dist/electron/main.js +5 -0
- package/dist/electron/preload.js +1 -0
- package/dist/icon.png +0 -0
- package/dist/index.html +27 -0
- package/docs/CODEBASE_ANALYSIS_REPORT.md +309 -0
- package/docs/DEBUG_LOGGING_GUIDE.md +244 -0
- package/docs/README.md +115 -0
- package/docs/TOC_WIRING_GUIDE.md +344 -0
- package/docs/analysis/Bullet_Symbol_Bug_Analysis.md +136 -0
- package/docs/analysis/DOCXMLATER_ANALYSIS_SUMMARY.txt +169 -0
- package/docs/analysis/Document_Processing_Issues_Analysis.md +704 -0
- package/docs/analysis/FIELD_PRESERVATION_ANALYSIS.md +1200 -0
- package/docs/analysis/INDENTATION_PRESERVE_ANALYSIS.md +181 -0
- package/docs/analysis/INDENTATION_PRESERVE_IMPLEMENTATION.md +207 -0
- package/docs/analysis/List_Implementation.md +206 -0
- package/docs/analysis/List_Implementation_Accuracy_Report.md +366 -0
- package/docs/analysis/PROCESSING_OPTIONS_UI_UPDATES.md +220 -0
- package/docs/analysis/RefactorStyles.md +852 -0
- package/docs/analysis/STYLE_PARAMETER_ENHANCEMENT.md +143 -0
- package/docs/analysis/docxmlater-comparison-todo-2025-11-13.md +636 -0
- package/docs/analysis/docxmlater-implementation-analysis-2025-11-13.md +340 -0
- package/docs/analysis/docxmlater-template_ui-integration-analysis.md +263 -0
- package/docs/analysis/github-issues-to-create.md +237 -0
- package/docs/api/API_README.md +538 -0
- package/docs/api/API_REFERENCE.md +751 -0
- package/docs/api/TYPE_DEFINITIONS.md +869 -0
- package/docs/architecture/FONT_EMBEDDING_GUIDE.md +318 -0
- package/docs/architecture/docxmlater-functions-and-structure.md +726 -0
- package/docs/docxmlater-readme.md +1341 -0
- package/docs/fixes/EXECUTION_LOG_TEST_BASE.md +573 -0
- package/docs/fixes/HYPERLINK_TEXT_SANITIZATION.md +253 -0
- package/docs/fixes/README.md +37 -0
- package/docs/github-issues/issue-1-body.md +125 -0
- package/docs/github-issues/issue-10-body.md +850 -0
- package/docs/github-issues/issue-2-body.md +200 -0
- package/docs/github-issues/issue-3-body.md +270 -0
- package/docs/github-issues/issue-4-body.md +169 -0
- package/docs/github-issues/issue-5-body.md +173 -0
- package/docs/github-issues/issue-6-body.md +158 -0
- package/docs/github-issues/issue-7-body.md +171 -0
- package/docs/github-issues/issue-8-body.md +407 -0
- package/docs/github-issues/issue-9-body.md +515 -0
- package/docs/github-issues/issue-tracker.md +274 -0
- package/docs/github-issues/predictive-analysis-2025-10-18.md +2131 -0
- package/docs/implementation/List_Framework_Refactor_Plan.md +336 -0
- package/docs/implementation/PRIMARY_TEXT_COLOR_FEATURE.md +217 -0
- package/docs/implementation/RELEASE_PLAN_v2.1.0.md +362 -0
- package/docs/implementation/RefactorStyles.md +588 -0
- package/docs/implementation/implement-plan.md +489 -0
- package/docs/implementation/missing-helpers-implementation.md +391 -0
- package/docs/implementation/refactor-plan.md +520 -0
- package/docs/implementation/session-implementation-complete.md +233 -0
- package/docs/implementation/session-management-plan.md +250 -0
- package/docs/setup-checklist.md +77 -0
- package/docs/versions/changelog.md +345 -0
- package/electron/customUpdater.ts +656 -0
- package/electron/main.ts +2441 -0
- package/electron/memoryConfig.ts +187 -0
- package/electron/preload.ts +394 -0
- package/electron/proxyConfig.ts +340 -0
- package/electron/services/BackupService.ts +452 -0
- package/electron/services/DictionaryService.ts +402 -0
- package/electron/services/LocalDictionaryLookupService.ts +147 -0
- package/electron/services/PowerAutomateApiService.ts +231 -0
- package/electron/services/SharePointSyncService.ts +474 -0
- package/electron/windowsCertStore.ts +427 -0
- package/electron/zscalerConfig.ts +381 -0
- package/eslint.config.js +92 -0
- package/jest.config.js +52 -0
- package/package.json +214 -0
- package/postcss.config.mjs +6 -0
- package/public/icon.png +0 -0
- package/publish-release.ps1 +5 -0
- package/renovate.json +30 -0
- package/src/App.tsx +216 -0
- package/src/__mocks__/p-limit.js +12 -0
- package/src/__mocks__/styleMock.js +1 -0
- package/src/components/common/BugReportButton.tsx +44 -0
- package/src/components/common/BugReportDialog.tsx +193 -0
- package/src/components/common/Button.tsx +153 -0
- package/src/components/common/Card.tsx +86 -0
- package/src/components/common/ColorPickerDialog.tsx +177 -0
- package/src/components/common/ConfirmDialog.tsx +96 -0
- package/src/components/common/DebugConsole.tsx +275 -0
- package/src/components/common/EmptyState.tsx +183 -0
- package/src/components/common/ErrorBoundary.tsx +98 -0
- package/src/components/common/ErrorDetailsDialog.tsx +153 -0
- package/src/components/common/ErrorFallback.tsx +218 -0
- package/src/components/common/Input.tsx +109 -0
- package/src/components/common/Skeleton.tsx +184 -0
- package/src/components/common/SplashScreen.tsx +81 -0
- package/src/components/common/Toast.tsx +155 -0
- package/src/components/common/Tooltip.tsx +79 -0
- package/src/components/common/UpdateNotification.tsx +320 -0
- package/src/components/comparison/ComparisonWindow.tsx +374 -0
- package/src/components/comparison/SideBySideDiff.tsx +486 -0
- package/src/components/comparison/index.ts +8 -0
- package/src/components/document/DocumentUploader.tsx +288 -0
- package/src/components/document/HyperlinkPreview.tsx +430 -0
- package/src/components/document/HyperlinkService.md +1484 -0
- package/src/components/document/Hyperlink_Technical_Documentation.md +496 -0
- package/src/components/document/InlineChangesView.tsx +707 -0
- package/src/components/document/ProcessingProgress.tsx +303 -0
- package/src/components/document/ProcessingResults.tsx +256 -0
- package/src/components/document/TrackedChangesDetail.tsx +530 -0
- package/src/components/document/TrackedChangesPanel.tsx +546 -0
- package/src/components/document/VirtualDocumentList.tsx +240 -0
- package/src/components/editor/DocumentEditor.tsx +723 -0
- package/src/components/editor/DocumentEditorModal.tsx +640 -0
- package/src/components/editor/EditorQuickActions.tsx +502 -0
- package/src/components/editor/EditorToolbar.tsx +312 -0
- package/src/components/editor/TableEditor.tsx +926 -0
- package/src/components/editor/index.ts +18 -0
- package/src/components/layout/Header.tsx +190 -0
- package/src/components/layout/Sidebar.tsx +313 -0
- package/src/components/layout/TitleBar.tsx +190 -0
- package/src/components/navigation/CommandPalette.tsx +233 -0
- package/src/components/navigation/KeyboardShortcutsModal.tsx +173 -0
- package/src/components/sessions/ChangeItem.tsx +408 -0
- package/src/components/sessions/ChangeViewer.tsx +1155 -0
- package/src/components/sessions/DocumentComparisonModal.tsx +314 -0
- package/src/components/sessions/ProcessingOptions.tsx +297 -0
- package/src/components/sessions/ReplacementsTab.tsx +438 -0
- package/src/components/sessions/RevisionHandlingOptions.tsx +87 -0
- package/src/components/sessions/SessionManager.tsx +188 -0
- package/src/components/sessions/StylesEditor.tsx +1335 -0
- package/src/components/sessions/TabContainer.tsx +151 -0
- package/src/components/sessions/VirtualSessionList.tsx +157 -0
- package/src/components/sessions/sessionToProcessorManager.tsx +420 -0
- package/src/components/settings/CertificateManager.tsx +410 -0
- package/src/components/settings/SegmentedControl.tsx +88 -0
- package/src/components/settings/SettingRow.tsx +52 -0
- package/src/contexts/GlobalStatsContext.tsx +396 -0
- package/src/contexts/SessionContext.tsx +2129 -0
- package/src/contexts/ThemeContext.tsx +428 -0
- package/src/contexts/UserSettingsContext.tsx +290 -0
- package/src/contexts/__tests__/GlobalStatsContext.test.tsx +390 -0
- package/src/global.d.ts +273 -0
- package/src/hooks/useDocumentQueue.tsx +210 -0
- package/src/hooks/useToast.tsx +55 -0
- package/src/main.tsx +10 -0
- package/src/pages/Analytics.tsx +386 -0
- package/src/pages/CurrentSession.tsx +1174 -0
- package/src/pages/Dashboard.tsx +319 -0
- package/src/pages/Documents.tsx +317 -0
- package/src/pages/Projects.tsx +250 -0
- package/src/pages/Reporting.tsx +386 -0
- package/src/pages/Search.tsx +349 -0
- package/src/pages/Sessions.tsx +285 -0
- package/src/pages/Settings.tsx +2662 -0
- package/src/services/HyperlinkService.ts +1085 -0
- package/src/services/document/DocXMLaterProcessor.ts +617 -0
- package/src/services/document/DocumentProcessingComparison.ts +856 -0
- package/src/services/document/DocumentSnapshotService.ts +575 -0
- package/src/services/document/WordDocumentProcessor.ts +10509 -0
- package/src/services/document/__tests__/DocXMLaterProcessor.hyperlinks.test.md +311 -0
- package/src/services/document/__tests__/WordDocumentProcessor.integration.test.ts +515 -0
- package/src/services/document/__tests__/WordDocumentProcessor.test.ts +812 -0
- package/src/services/document/blanklines/BlankLineManager.ts +658 -0
- package/src/services/document/blanklines/__tests__/paragraphChecks.test.ts +281 -0
- package/src/services/document/blanklines/helpers/blankLineInsertion.ts +87 -0
- package/src/services/document/blanklines/helpers/blankLineSnapshot.ts +251 -0
- package/src/services/document/blanklines/helpers/clearCustom.ts +121 -0
- package/src/services/document/blanklines/helpers/contextChecks.ts +117 -0
- package/src/services/document/blanklines/helpers/imageChecks.ts +51 -0
- package/src/services/document/blanklines/helpers/paragraphChecks.ts +236 -0
- package/src/services/document/blanklines/helpers/removeBlanksBetweenListItems.ts +91 -0
- package/src/services/document/blanklines/helpers/removeTrailingBlanks.ts +35 -0
- package/src/services/document/blanklines/helpers/tableGuards.ts +21 -0
- package/src/services/document/blanklines/index.ts +67 -0
- package/src/services/document/blanklines/rules/additionRules.ts +337 -0
- package/src/services/document/blanklines/rules/indentationRules.ts +317 -0
- package/src/services/document/blanklines/rules/removalRules.ts +362 -0
- package/src/services/document/blanklines/rules/ruleTypes.ts +92 -0
- package/src/services/document/blanklines/types.ts +29 -0
- package/src/services/document/helpers/ImageBorderCropper.ts +377 -0
- package/src/services/document/helpers/__tests__/whitespace.test.ts +272 -0
- package/src/services/document/helpers/whitespace.ts +117 -0
- package/src/services/document/list/ListNormalizer.ts +947 -0
- package/src/services/document/list/index.ts +45 -0
- package/src/services/document/list/list-detection.ts +275 -0
- package/src/services/document/list/list-types.ts +162 -0
- package/src/services/document/processors/HyperlinkProcessor.ts +370 -0
- package/src/services/document/processors/ListProcessor.ts +257 -0
- package/src/services/document/processors/StructureProcessor.ts +176 -0
- package/src/services/document/processors/StyleProcessor.ts +389 -0
- package/src/services/document/processors/TableProcessor.ts +2238 -0
- package/src/services/document/processors/__tests__/HyperlinkProcessor.test.ts +314 -0
- package/src/services/document/processors/__tests__/ListProcessor.test.ts +291 -0
- package/src/services/document/processors/__tests__/StructureProcessor.test.ts +257 -0
- package/src/services/document/processors/__tests__/TableProcessor.hlp-tips-bullets.test.ts +459 -0
- package/src/services/document/processors/__tests__/TableProcessor.test.ts +1604 -0
- package/src/services/document/processors/index.ts +28 -0
- package/src/services/document/types/docx-processing.ts +310 -0
- package/src/services/editor/EditorActionHandlers.ts +901 -0
- package/src/services/editor/index.ts +13 -0
- package/src/setupTests.ts +47 -0
- package/src/styles/global.css +782 -0
- package/src/types/backup.ts +132 -0
- package/src/types/dictionary.ts +125 -0
- package/src/types/document-processing.ts +331 -0
- package/src/types/docxmlater-augments.d.ts +142 -0
- package/src/types/editor.ts +280 -0
- package/src/types/electron.ts +340 -0
- package/src/types/globalStats.ts +155 -0
- package/src/types/hyperlink.ts +471 -0
- package/src/types/operations.ts +354 -0
- package/src/types/session.ts +427 -0
- package/src/types/settings.ts +112 -0
- package/src/utils/MemoryMonitor.ts +248 -0
- package/src/utils/cn.ts +6 -0
- package/src/utils/colorConvert.ts +306 -0
- package/src/utils/diffUtils.ts +347 -0
- package/src/utils/documentUtils.ts +202 -0
- package/src/utils/electronGuard.ts +62 -0
- package/src/utils/indexedDB.ts +915 -0
- package/src/utils/logger.ts +717 -0
- package/src/utils/pathSecurity.ts +232 -0
- package/src/utils/pathValidator.ts +236 -0
- package/src/utils/processingTimeEstimator.ts +153 -0
- package/src/utils/safeJsonParse.ts +62 -0
- package/src/utils/textSanitizer.ts +162 -0
- package/src/utils/urlHelpers.ts +304 -0
- package/src/utils/urlPatterns.ts +198 -0
- package/src/utils/urlSanitizer.ts +152 -0
- package/src/vite-env.d.ts +11 -0
- package/tsconfig.electron.json +19 -0
- package/tsconfig.json +36 -0
- package/tsconfig.node.json +12 -0
- package/typedoc.json +45 -0
- package/vite.config.ts +152 -0
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import { app } from 'electron';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as os from 'os';
|
|
5
|
+
import { exec } from 'child_process';
|
|
6
|
+
import { promisify } from 'util';
|
|
7
|
+
import { logger } from '../src/utils/logger';
|
|
8
|
+
|
|
9
|
+
const execAsync = promisify(exec);
|
|
10
|
+
const log = logger.namespace('ZscalerConfig');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Zscaler-specific configuration for handling SSL inspection
|
|
14
|
+
* This module detects and configures Zscaler root certificates
|
|
15
|
+
*/
|
|
16
|
+
export class ZscalerConfig {
|
|
17
|
+
private zscalerCertPath: string | null = null;
|
|
18
|
+
private isZscalerDetected: boolean = false;
|
|
19
|
+
private certificateContent: string | null = null;
|
|
20
|
+
|
|
21
|
+
constructor() {
|
|
22
|
+
this.detectZscaler();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Common locations where Zscaler root certificate might be stored
|
|
27
|
+
*/
|
|
28
|
+
private getCommonCertPaths(): string[] {
|
|
29
|
+
const homeDir = os.homedir();
|
|
30
|
+
const paths: string[] = [];
|
|
31
|
+
|
|
32
|
+
if (process.platform === 'win32') {
|
|
33
|
+
paths.push(
|
|
34
|
+
// Common Zscaler certificate locations on Windows
|
|
35
|
+
path.join('C:', 'Zscaler', 'ZscalerRootCertificate.crt'),
|
|
36
|
+
path.join('C:', 'Zscaler', 'ZscalerRootCertificate.pem'),
|
|
37
|
+
path.join('C:', 'Program Files', 'Zscaler', 'ZSAInstaller', 'ZscalerRootCertificate.crt'),
|
|
38
|
+
path.join('C:', 'Program Files (x86)', 'Zscaler', 'ZSAInstaller', 'ZscalerRootCertificate.crt'),
|
|
39
|
+
path.join(homeDir, 'AppData', 'Local', 'Zscaler', 'ZscalerRootCertificate.crt'),
|
|
40
|
+
path.join(homeDir, 'AppData', 'Local', 'Zscaler', 'ZscalerRootCertificate.pem'),
|
|
41
|
+
// Sometimes IT departments place it here
|
|
42
|
+
path.join(homeDir, '.zscaler', 'cert.pem'),
|
|
43
|
+
path.join(homeDir, '.zscaler', 'ZscalerRootCA.pem'),
|
|
44
|
+
path.join(homeDir, 'zscaler.pem'),
|
|
45
|
+
path.join(homeDir, 'zscaler-cert.pem'),
|
|
46
|
+
// Corporate standard locations
|
|
47
|
+
path.join('C:', 'certs', 'ZscalerRootCA.pem'),
|
|
48
|
+
path.join('C:', 'certificates', 'zscaler.pem')
|
|
49
|
+
);
|
|
50
|
+
} else if (process.platform === 'darwin') {
|
|
51
|
+
paths.push(
|
|
52
|
+
// macOS locations
|
|
53
|
+
path.join('/Library', 'Application Support', 'Zscaler', 'cert', 'ZscalerRootCertificate.pem'),
|
|
54
|
+
path.join(homeDir, 'Library', 'Application Support', 'Zscaler', 'cert', 'ZscalerRootCertificate.pem'),
|
|
55
|
+
path.join(homeDir, '.zscaler', 'cert.pem'),
|
|
56
|
+
path.join('/usr/local/share/ca-certificates', 'Zscaler_Root_CA.crt')
|
|
57
|
+
);
|
|
58
|
+
} else {
|
|
59
|
+
// Linux
|
|
60
|
+
paths.push(
|
|
61
|
+
path.join('/usr/local/share/ca-certificates', 'Zscaler_Root_CA.crt'),
|
|
62
|
+
path.join('/etc/ssl/certs', 'Zscaler_Root_CA.pem'),
|
|
63
|
+
path.join(homeDir, '.zscaler', 'cert.pem')
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Also check environment variable
|
|
68
|
+
const envCertPath = process.env.ZSCALER_CERT_PATH || process.env.ZSCALER_CERT;
|
|
69
|
+
if (envCertPath) {
|
|
70
|
+
paths.unshift(envCertPath);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return paths;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Detect if Zscaler is present and find its certificate
|
|
78
|
+
*/
|
|
79
|
+
private async detectZscaler(): Promise<void> {
|
|
80
|
+
log.info('[ZscalerConfig] Detecting Zscaler presence...');
|
|
81
|
+
|
|
82
|
+
// Check environment variables that indicate Zscaler
|
|
83
|
+
const zscalerEnvVars = [
|
|
84
|
+
'ZSCALER_CERT_PATH',
|
|
85
|
+
'ZSCALER_CERT',
|
|
86
|
+
'ZSCALER_BYPASS',
|
|
87
|
+
'ZS_SDK_HOME',
|
|
88
|
+
'ZAPP_HOME'
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
for (const envVar of zscalerEnvVars) {
|
|
92
|
+
if (process.env[envVar]) {
|
|
93
|
+
log.info(` Detected Zscaler environment variable: ${envVar}`);
|
|
94
|
+
this.isZscalerDetected = true;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Check for Zscaler processes (Windows)
|
|
100
|
+
if (process.platform === 'win32') {
|
|
101
|
+
try {
|
|
102
|
+
const { stdout } = await execAsync('tasklist /FI "IMAGENAME eq ZSATunnel.exe"');
|
|
103
|
+
if (stdout.includes('ZSATunnel.exe')) {
|
|
104
|
+
log.info('[ZscalerConfig] Detected Zscaler process running');
|
|
105
|
+
this.isZscalerDetected = true;
|
|
106
|
+
}
|
|
107
|
+
} catch (error) {
|
|
108
|
+
// Ignore if command fails
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// NEW: Check Windows registry for Zscaler installation
|
|
112
|
+
try {
|
|
113
|
+
const { stdout: regOutput } = await execAsync(
|
|
114
|
+
'reg query "HKLM\\SOFTWARE\\Zscaler" 2>nul || reg query "HKCU\\SOFTWARE\\Zscaler" 2>nul'
|
|
115
|
+
);
|
|
116
|
+
if (regOutput && regOutput.length > 0) {
|
|
117
|
+
log.info('[ZscalerConfig] Detected Zscaler in Windows registry');
|
|
118
|
+
this.isZscalerDetected = true;
|
|
119
|
+
}
|
|
120
|
+
} catch {
|
|
121
|
+
// Registry key doesn't exist, continue
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Look for Zscaler certificate on disk first
|
|
126
|
+
const certPaths = this.getCommonCertPaths();
|
|
127
|
+
for (const certPath of certPaths) {
|
|
128
|
+
if (fs.existsSync(certPath)) {
|
|
129
|
+
log.info(` Found Zscaler certificate at: ${certPath}`);
|
|
130
|
+
this.zscalerCertPath = certPath;
|
|
131
|
+
this.isZscalerDetected = true;
|
|
132
|
+
|
|
133
|
+
// Read certificate content
|
|
134
|
+
try {
|
|
135
|
+
this.certificateContent = fs.readFileSync(certPath, 'utf8');
|
|
136
|
+
log.info('[ZscalerConfig] Successfully loaded Zscaler certificate from disk');
|
|
137
|
+
} catch (error) {
|
|
138
|
+
log.error('[ZscalerConfig] Failed to read certificate:', error);
|
|
139
|
+
}
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// NEW: If no certificate found on disk, try Windows Certificate Store
|
|
145
|
+
if (!this.zscalerCertPath && process.platform === 'win32') {
|
|
146
|
+
log.info('[ZscalerConfig] No certificate found on disk, checking Windows Certificate Store...');
|
|
147
|
+
try {
|
|
148
|
+
// Dynamically import windowsCertStore to avoid static import warning
|
|
149
|
+
const { windowsCertStore } = await import('./windowsCertStore');
|
|
150
|
+
const certFromStore = await windowsCertStore.findZscalerCertificate();
|
|
151
|
+
if (certFromStore) {
|
|
152
|
+
log.info(` Found Zscaler certificate in Windows store: ${certFromStore}`);
|
|
153
|
+
this.zscalerCertPath = certFromStore;
|
|
154
|
+
this.isZscalerDetected = true;
|
|
155
|
+
|
|
156
|
+
// Read the exported certificate
|
|
157
|
+
if (fs.existsSync(certFromStore)) {
|
|
158
|
+
this.certificateContent = fs.readFileSync(certFromStore, 'utf8');
|
|
159
|
+
log.info('[ZscalerConfig] Successfully loaded certificate from Windows store');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
} catch (error) {
|
|
163
|
+
log.error('[ZscalerConfig] Error accessing Windows Certificate Store:', error);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check if NODE_EXTRA_CA_CERTS is already set
|
|
168
|
+
if (process.env.NODE_EXTRA_CA_CERTS) {
|
|
169
|
+
log.info(` NODE_EXTRA_CA_CERTS already set to: ${process.env.NODE_EXTRA_CA_CERTS}`);
|
|
170
|
+
// Check if it points to a Zscaler cert
|
|
171
|
+
const certPath = process.env.NODE_EXTRA_CA_CERTS;
|
|
172
|
+
if (fs.existsSync(certPath)) {
|
|
173
|
+
const content = fs.readFileSync(certPath, 'utf8');
|
|
174
|
+
if (content.includes('Zscaler') || content.includes('ZSCALER')) {
|
|
175
|
+
log.info('[ZscalerConfig] NODE_EXTRA_CA_CERTS points to Zscaler certificate');
|
|
176
|
+
this.isZscalerDetected = true;
|
|
177
|
+
this.zscalerCertPath = certPath;
|
|
178
|
+
this.certificateContent = content;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (this.isZscalerDetected) {
|
|
184
|
+
log.info('[ZscalerConfig] Zscaler detected - special handling will be applied');
|
|
185
|
+
} else {
|
|
186
|
+
log.info('[ZscalerConfig] Zscaler not detected');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Configure application for Zscaler
|
|
192
|
+
*/
|
|
193
|
+
public configureApp(): void {
|
|
194
|
+
if (!this.isZscalerDetected) {
|
|
195
|
+
log.info('[ZscalerConfig] Zscaler not detected, skipping configuration');
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
log.info('[ZscalerConfig] Configuring app for Zscaler...');
|
|
200
|
+
|
|
201
|
+
// Set NODE_EXTRA_CA_CERTS if we found a certificate
|
|
202
|
+
if (this.zscalerCertPath && !process.env.NODE_EXTRA_CA_CERTS) {
|
|
203
|
+
process.env.NODE_EXTRA_CA_CERTS = this.zscalerCertPath;
|
|
204
|
+
log.info(` Set NODE_EXTRA_CA_CERTS to: ${this.zscalerCertPath}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Configure Chromium to be more lenient with certificates
|
|
208
|
+
app.commandLine.appendSwitch('ignore-certificate-errors-spki-list', 'base64-encoded-spki');
|
|
209
|
+
|
|
210
|
+
// Allow insecure connections to GitHub (Zscaler often causes issues with GitHub)
|
|
211
|
+
app.commandLine.appendSwitch('allow-insecure-localhost');
|
|
212
|
+
|
|
213
|
+
// Disable certificate transparency checks (Zscaler certificates often fail these)
|
|
214
|
+
app.commandLine.appendSwitch('disable-features', 'CertificateTransparencyEnforcement');
|
|
215
|
+
|
|
216
|
+
// Set Zscaler bypass flag
|
|
217
|
+
if (!process.env.ZSCALER_BYPASS) {
|
|
218
|
+
process.env.ZSCALER_BYPASS = 'true';
|
|
219
|
+
log.info('[ZscalerConfig] Set ZSCALER_BYPASS flag');
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Get special headers for Zscaler bypass
|
|
225
|
+
*/
|
|
226
|
+
public getBypassHeaders(): Record<string, string> {
|
|
227
|
+
if (!this.isZscalerDetected) {
|
|
228
|
+
return {};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const headers: Record<string, string> = {
|
|
232
|
+
// Zscaler-specific bypass headers
|
|
233
|
+
'X-Zscaler-Bypass': 'true',
|
|
234
|
+
'X-Zscaler-Bypass-Inspection': 'true',
|
|
235
|
+
'X-BlueCoat-Via': 'bypass',
|
|
236
|
+
'X-Forwarded-For': '127.0.0.1',
|
|
237
|
+
'X-Real-IP': '127.0.0.1',
|
|
238
|
+
|
|
239
|
+
// Mutual TLS authentication headers (for MSDTC/EAP-TLS)
|
|
240
|
+
'X-MS-CertAuth': 'true',
|
|
241
|
+
'X-ARR-ClientCert': 'required',
|
|
242
|
+
'X-SSL-Client-Verify': 'SUCCESS',
|
|
243
|
+
|
|
244
|
+
// Corporate proxy bypass headers
|
|
245
|
+
'X-Corporate-Bypass': 'software-update',
|
|
246
|
+
'X-Update-Agent': 'DocumentationHub',
|
|
247
|
+
|
|
248
|
+
// GitHub-specific headers that might be whitelisted
|
|
249
|
+
'X-GitHub-Request-Id': `dochub-${Date.now()}`,
|
|
250
|
+
'X-GitHub-Media-Type': 'github.v3',
|
|
251
|
+
|
|
252
|
+
// Some Zscaler configurations respect npm/package manager user agents
|
|
253
|
+
'User-Agent': `npm/8.0.0 node/${process.version} ${process.platform} ${process.arch} DocumentationHub/${app.getVersion()}`
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// If we have a Zscaler API token (from environment), add it
|
|
257
|
+
const zscalerToken = process.env.ZSCALER_API_TOKEN || process.env.ZS_API_TOKEN;
|
|
258
|
+
if (zscalerToken) {
|
|
259
|
+
headers['X-Zscaler-API-Token'] = zscalerToken;
|
|
260
|
+
log.info('[ZscalerConfig] Added Zscaler API token to bypass headers');
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// If we have a bypass code from IT department
|
|
264
|
+
const bypassCode = process.env.ZSCALER_BYPASS_CODE || process.env.CORPORATE_BYPASS_CODE;
|
|
265
|
+
if (bypassCode) {
|
|
266
|
+
headers['X-Bypass-Code'] = bypassCode;
|
|
267
|
+
log.info('[ZscalerConfig] Added corporate bypass code to headers');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return headers;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Check if Zscaler is causing certificate errors
|
|
275
|
+
*/
|
|
276
|
+
public isZscalerError(error: any): boolean {
|
|
277
|
+
if (!error) return false;
|
|
278
|
+
|
|
279
|
+
const errorMessage = error.message?.toLowerCase() || '';
|
|
280
|
+
const errorCode = error.code || '';
|
|
281
|
+
|
|
282
|
+
const zscalerIndicators = [
|
|
283
|
+
'zscaler',
|
|
284
|
+
'unable to get local issuer certificate',
|
|
285
|
+
'self signed certificate in certificate chain',
|
|
286
|
+
'unable_to_get_issuer_cert_locally',
|
|
287
|
+
'self_signed_cert_in_chain',
|
|
288
|
+
'depth zero self signed cert',
|
|
289
|
+
'certificate verify failed',
|
|
290
|
+
// Common with Zscaler
|
|
291
|
+
'err_cert_authority_invalid',
|
|
292
|
+
'err_cert_common_name_invalid'
|
|
293
|
+
];
|
|
294
|
+
|
|
295
|
+
return zscalerIndicators.some(indicator =>
|
|
296
|
+
errorMessage.includes(indicator) || errorCode.toLowerCase().includes(indicator)
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Get certificate content for injection
|
|
302
|
+
*/
|
|
303
|
+
public getCertificateContent(): string | null {
|
|
304
|
+
return this.certificateContent;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Check if Zscaler is detected
|
|
309
|
+
*/
|
|
310
|
+
public isDetected(): boolean {
|
|
311
|
+
return this.isZscalerDetected;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Get Zscaler certificate path
|
|
316
|
+
*/
|
|
317
|
+
public getCertPath(): string | null {
|
|
318
|
+
return this.zscalerCertPath;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Create a combined certificate bundle
|
|
323
|
+
*/
|
|
324
|
+
public async createCertBundle(): Promise<string | null> {
|
|
325
|
+
if (!this.certificateContent) {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
try {
|
|
330
|
+
const tempDir = app.getPath('temp');
|
|
331
|
+
const bundlePath = path.join(tempDir, 'zscaler-cert-bundle.pem');
|
|
332
|
+
|
|
333
|
+
// Get system certificates if available
|
|
334
|
+
let systemCerts = '';
|
|
335
|
+
if (process.platform === 'win32') {
|
|
336
|
+
// On Windows, we might need to export system certs
|
|
337
|
+
try {
|
|
338
|
+
const { stdout } = await execAsync('certutil -store -silent Root');
|
|
339
|
+
// This would need more processing to extract actual certificates
|
|
340
|
+
log.info('[ZscalerConfig] System certificates available');
|
|
341
|
+
} catch (e) {
|
|
342
|
+
// Ignore
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Combine certificates
|
|
347
|
+
const bundle = this.certificateContent + '\n' + systemCerts;
|
|
348
|
+
// PEM files are text files, use UTF-8 encoding
|
|
349
|
+
fs.writeFileSync(bundlePath, bundle, 'utf-8');
|
|
350
|
+
|
|
351
|
+
log.info(` Created certificate bundle at: ${bundlePath}`);
|
|
352
|
+
return bundlePath;
|
|
353
|
+
} catch (error) {
|
|
354
|
+
log.error('[ZscalerConfig] Failed to create certificate bundle:', error);
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Log Zscaler configuration for debugging
|
|
361
|
+
*/
|
|
362
|
+
public logConfiguration(): void {
|
|
363
|
+
log.info('[ZscalerConfig] Configuration Summary:');
|
|
364
|
+
log.info(` - Zscaler Detected: ${this.isZscalerDetected}`);
|
|
365
|
+
log.info(` - Certificate Path: ${this.zscalerCertPath || 'Not found'}`);
|
|
366
|
+
log.info(` - Certificate Loaded: ${this.certificateContent ? 'Yes' : 'No'}`);
|
|
367
|
+
log.info(` - NODE_EXTRA_CA_CERTS: ${process.env.NODE_EXTRA_CA_CERTS || 'Not set'}`);
|
|
368
|
+
log.info(` - ZSCALER_BYPASS: ${process.env.ZSCALER_BYPASS || 'Not set'}`);
|
|
369
|
+
|
|
370
|
+
if (this.isZscalerDetected && !this.zscalerCertPath) {
|
|
371
|
+
log.info('[ZscalerConfig] WARNING: Zscaler detected but certificate not found!');
|
|
372
|
+
log.info('[ZscalerConfig] You may need to:');
|
|
373
|
+
log.info(' 1. Export Zscaler certificate from your browser');
|
|
374
|
+
log.info(' 2. Save it as C:\\Zscaler\\ZscalerRootCertificate.pem');
|
|
375
|
+
log.info(' 3. Or set ZSCALER_CERT_PATH environment variable');
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Export singleton instance
|
|
381
|
+
export const zscalerConfig = new ZscalerConfig();
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import typescript from '@typescript-eslint/eslint-plugin';
|
|
3
|
+
import typescriptParser from '@typescript-eslint/parser';
|
|
4
|
+
import react from 'eslint-plugin-react';
|
|
5
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
6
|
+
import prettier from 'eslint-config-prettier';
|
|
7
|
+
|
|
8
|
+
export default [
|
|
9
|
+
{
|
|
10
|
+
ignores: [
|
|
11
|
+
'dist/**',
|
|
12
|
+
'build/**',
|
|
13
|
+
'node_modules/**',
|
|
14
|
+
'GH_Issues/scratchpads/**',
|
|
15
|
+
'*.min.js',
|
|
16
|
+
'coverage/**',
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
js.configs.recommended,
|
|
20
|
+
prettier,
|
|
21
|
+
{
|
|
22
|
+
files: ['**/*.{ts,tsx,js,jsx}'],
|
|
23
|
+
languageOptions: {
|
|
24
|
+
parser: typescriptParser,
|
|
25
|
+
parserOptions: {
|
|
26
|
+
ecmaVersion: 'latest',
|
|
27
|
+
sourceType: 'module',
|
|
28
|
+
ecmaFeatures: {
|
|
29
|
+
jsx: true,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
globals: {
|
|
33
|
+
// Browser globals
|
|
34
|
+
window: 'readonly',
|
|
35
|
+
document: 'readonly',
|
|
36
|
+
navigator: 'readonly',
|
|
37
|
+
console: 'readonly',
|
|
38
|
+
setTimeout: 'readonly',
|
|
39
|
+
clearTimeout: 'readonly',
|
|
40
|
+
setInterval: 'readonly',
|
|
41
|
+
clearInterval: 'readonly',
|
|
42
|
+
requestAnimationFrame: 'readonly',
|
|
43
|
+
cancelAnimationFrame: 'readonly',
|
|
44
|
+
localStorage: 'readonly',
|
|
45
|
+
sessionStorage: 'readonly',
|
|
46
|
+
// Node globals
|
|
47
|
+
process: 'readonly',
|
|
48
|
+
Buffer: 'readonly',
|
|
49
|
+
__dirname: 'readonly',
|
|
50
|
+
__filename: 'readonly',
|
|
51
|
+
module: 'readonly',
|
|
52
|
+
require: 'readonly',
|
|
53
|
+
global: 'readonly',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
plugins: {
|
|
57
|
+
'@typescript-eslint': typescript,
|
|
58
|
+
react: react,
|
|
59
|
+
'react-hooks': reactHooks,
|
|
60
|
+
},
|
|
61
|
+
rules: {
|
|
62
|
+
// TypeScript rules
|
|
63
|
+
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
64
|
+
'@typescript-eslint/no-unused-vars': [
|
|
65
|
+
'warn',
|
|
66
|
+
{
|
|
67
|
+
argsIgnorePattern: '^_',
|
|
68
|
+
varsIgnorePattern: '^_',
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
'@typescript-eslint/no-explicit-any': 'warn',
|
|
72
|
+
|
|
73
|
+
// React rules
|
|
74
|
+
'react/react-in-jsx-scope': 'off',
|
|
75
|
+
'react/prop-types': 'off',
|
|
76
|
+
'react/display-name': 'off',
|
|
77
|
+
|
|
78
|
+
// React Hooks rules
|
|
79
|
+
'react-hooks/rules-of-hooks': 'error',
|
|
80
|
+
'react-hooks/exhaustive-deps': 'warn',
|
|
81
|
+
|
|
82
|
+
// General rules
|
|
83
|
+
'no-unused-vars': 'off', // Using TypeScript's no-unused-vars instead
|
|
84
|
+
'no-undef': 'off', // TypeScript handles this
|
|
85
|
+
},
|
|
86
|
+
settings: {
|
|
87
|
+
react: {
|
|
88
|
+
version: 'detect',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
];
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** @type {import('jest').Config} */
|
|
2
|
+
const config = {
|
|
3
|
+
preset: 'ts-jest',
|
|
4
|
+
testEnvironment: 'jsdom',
|
|
5
|
+
roots: ['<rootDir>/src'],
|
|
6
|
+
moduleNameMapper: {
|
|
7
|
+
'^@/(.*)$': '<rootDir>/src/$1',
|
|
8
|
+
'^@components/(.*)$': '<rootDir>/src/components/$1',
|
|
9
|
+
'^@hooks/(.*)$': '<rootDir>/src/hooks/$1',
|
|
10
|
+
'^@utils/(.*)$': '<rootDir>/src/utils/$1',
|
|
11
|
+
'^@styles/(.*)$': '<rootDir>/src/styles/$1',
|
|
12
|
+
'^@pages/(.*)$': '<rootDir>/src/pages/$1',
|
|
13
|
+
'^@contexts/(.*)$': '<rootDir>/src/contexts/$1',
|
|
14
|
+
'\\.(css|less|scss|sass)$': '<rootDir>/src/__mocks__/styleMock.js',
|
|
15
|
+
'^p-limit$': '<rootDir>/src/__mocks__/p-limit.js',
|
|
16
|
+
},
|
|
17
|
+
setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
|
|
18
|
+
testMatch: ['**/__tests__/**/*.test.{ts,tsx}', '**/*.test.{ts,tsx}'],
|
|
19
|
+
transform: {
|
|
20
|
+
'^.+\\.tsx?$': [
|
|
21
|
+
'ts-jest',
|
|
22
|
+
{
|
|
23
|
+
tsconfig: {
|
|
24
|
+
jsx: 'react-jsx',
|
|
25
|
+
esModuleInterop: true,
|
|
26
|
+
strict: true,
|
|
27
|
+
moduleResolution: 'node',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
transformIgnorePatterns: [
|
|
33
|
+
'/node_modules/(?!(p-limit|yocto-queue|lucide-react|framer-motion|@radix-ui|diff)/)',
|
|
34
|
+
],
|
|
35
|
+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
|
|
36
|
+
collectCoverageFrom: [
|
|
37
|
+
'src/**/*.{ts,tsx}',
|
|
38
|
+
'!src/**/*.d.ts',
|
|
39
|
+
'!src/main.tsx',
|
|
40
|
+
'!src/__mocks__/**',
|
|
41
|
+
],
|
|
42
|
+
coverageThreshold: {
|
|
43
|
+
global: {
|
|
44
|
+
branches: 50,
|
|
45
|
+
functions: 50,
|
|
46
|
+
lines: 50,
|
|
47
|
+
statements: 50,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
module.exports = config;
|