six-degrees 0.7.0 → 1.0.0
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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +1 -0
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +32 -4
- package/.next/standalone/.next/routes-manifest.json +6 -0
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +16 -16
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/admin-delete/route.js +1 -1
- package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/admin-update/route.js +1 -1
- package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bridges/route.js +1 -1
- package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bulk-import/route.js +1 -1
- package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/connections/route.js +1 -1
- package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/backup/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/csv/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/restore/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/delete-cluster/route.js +1 -1
- package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/ingest/route.js +1 -1
- package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/route.js +1 -1
- package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/outreach/route.js +3 -3
- package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/queue/route.js +1 -1
- package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/scraper/route.js +4 -4
- package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/setup-profile/route.js +1 -1
- package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/crm/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/social/route.js +1 -1
- package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/unlock/route.js +1 -1
- package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/update-images/route.js +1 -1
- package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/users/route.js +1 -1
- package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/import.html +1 -1
- package/.next/standalone/.next/server/app/import.rsc +18 -18
- package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +18 -18
- package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +19 -19
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +19 -19
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/insights/page/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/insights/page/build-manifest.json +20 -0
- package/.next/standalone/.next/server/app/insights/page/next-font-manifest.json +11 -0
- package/.next/standalone/.next/server/app/insights/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/.next/server/app/insights/page/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/insights/page.js +13 -0
- package/.next/standalone/.next/server/app/insights/page.js.map +5 -0
- package/.next/standalone/.next/server/app/insights/page.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/insights/page_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/insights.html +1 -0
- package/.next/standalone/.next/server/app/insights.meta +26 -0
- package/.next/standalone/.next/server/app/insights.rsc +35 -0
- package/.next/standalone/.next/server/app/insights.segments/_full.segment.rsc +35 -0
- package/.next/standalone/.next/server/app/insights.segments/_tree.segment.rsc +4 -0
- package/.next/standalone/.next/server/app/insights.segments/insights/__PAGE__.segment.rsc +33 -0
- package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/launch.html +2 -2
- package/.next/standalone/.next/server/app/launch.rsc +18 -18
- package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +18 -18
- package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/paths.html +1 -1
- package/.next/standalone/.next/server/app/paths.rsc +19 -19
- package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +19 -19
- package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/profile.html +1 -1
- package/.next/standalone/.next/server/app/profile.rsc +19 -19
- package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +19 -19
- package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/queue.html +1 -1
- package/.next/standalone/.next/server/app/queue.rsc +19 -19
- package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +19 -19
- package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +21 -20
- package/.next/standalone/.next/server/app/scores/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/scores/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/scores.html +1 -1
- package/.next/standalone/.next/server/app/scores.rsc +18 -18
- package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +18 -18
- package/.next/standalone/.next/server/app/scores.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/scores.segments/scores/__PAGE__.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings.html +1 -1
- package/.next/standalone/.next/server/app/settings.rsc +19 -19
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +19 -19
- package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/setup.html +1 -1
- package/.next/standalone/.next/server/app/setup.rsc +19 -19
- package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +19 -19
- package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/social/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/social.html +1 -1
- package/.next/standalone/.next/server/app/social.rsc +18 -18
- package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +18 -18
- package/.next/standalone/.next/server/app/social.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/social.segments/social/__PAGE__.segment.rsc +16 -16
- package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__063s0x7._.js → [root-of-the-server]__0r-0t-9._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ra6xyg._.js +15 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__20rwfdw._.js → [root-of-the-server]__0rcpjad._.js} +5 -2
- package/.next/standalone/.next/server/chunks/_1_fynia._.js +7 -7
- package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
- package/.next/standalone/.next/server/chunks/lib_02iz_9q._.js +2 -2
- package/.next/standalone/.next/server/chunks/lib_05agvk3._.js +2 -2
- package/.next/standalone/.next/server/chunks/lib_0v84u66._.js +2 -2
- package/.next/standalone/.next/server/chunks/lib_db-client_0_dch35.js +9 -9
- package/.next/standalone/.next/server/chunks/{lib_rpc_0jnfp2e.js → lib_rpc_00nndai.js} +1 -1
- package/.next/standalone/.next/server/chunks/{lib_rpc_0b17r6v.js → lib_rpc_03ibb-x.js} +1 -1
- package/.next/standalone/.next/server/chunks/{lib_rpc_0doq0t-.js → lib_rpc_03ri3ji.js} +1 -1
- package/.next/standalone/.next/server/chunks/{lib_rpc_0fd2rlw.js → lib_rpc_078ce48.js} +1 -1
- package/.next/standalone/.next/server/chunks/lib_rpc_0a69mgr.js +3 -0
- package/.next/standalone/.next/server/chunks/{lib_rpc_005abye.js → lib_rpc_0cej3t8.js} +1 -1
- package/.next/standalone/.next/server/chunks/lib_rpc_0cmh4g6.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0nx2_pc.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0r79-w1.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_0yx8ynd.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_12p-o9-.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1466dnb.js +3 -0
- package/.next/standalone/.next/server/chunks/{lib_rpc_0is4qoc.js → lib_rpc_1hjjjr4.js} +1 -1
- package/.next/standalone/.next/server/chunks/lib_rpc_1sryxv6.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1trn-x5.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_rpc_1ygu_mv.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0egamyq._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_04am_h8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_07zb7lu._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0_79idq._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0gds903._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0klqt9z._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_1k9qfsk._.js → _14jak5s._.js} +6 -2
- package/.next/standalone/.next/server/chunks/ssr/_14nxd3q._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1cj2yog._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1fm1ih_._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1hdqw0-._.js +7 -0
- package/.next/standalone/.next/server/chunks/ssr/_1k2nmbw._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0gy11ar._.js → _1r62six._.js} +6 -2
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_insights_page_actions_0-0tf75.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_components_0uuff77._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_components_1j3q-h5._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_01o3i5y._.js → app_components_settings_SectorPicker_1c-29qw.js} +2 -6
- package/.next/standalone/.next/server/chunks/ssr/app_components_ui_0pdmz2z.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_insights_page_1d_chja.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +14 -14
- package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +3 -3
- package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +4 -4
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware-manifest.json +5 -5
- package/.next/standalone/.next/server/next-font-manifest.js +1 -1
- package/.next/standalone/.next/server/next-font-manifest.json +4 -0
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/prefetch-hints.json +14 -0
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/02wnf8dkxegxg.js +34 -0
- package/.next/standalone/.next/static/chunks/0hggugbh84m4t.js +21 -0
- package/.next/{static/chunks/2eo9pqq9gay3r.js → standalone/.next/static/chunks/0ka4prpk3w9wn.js} +4 -4
- package/.next/standalone/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
- package/.next/standalone/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
- package/.next/{static/chunks/44yn0tcd9dfk3.js → standalone/.next/static/chunks/1bkt_hhjzvbh8.js} +1 -1
- package/.next/standalone/.next/static/chunks/1cmphb3kh2ers.css +3 -0
- package/.next/{static/chunks/1qbjermbf68xj.js → standalone/.next/static/chunks/1d8yv3k_atka7.js} +1 -1
- package/.next/standalone/.next/static/chunks/1ods5h86raivz.js +1 -0
- package/.next/standalone/.next/static/chunks/23hc51oa4vkhc.js +5 -0
- package/.next/standalone/.next/static/chunks/27n8k9wxlz5-7.js +1 -0
- package/.next/standalone/.next/static/chunks/{0p3g5tfostsep.js → 2q9i7pcxcnph1.js} +2 -2
- package/.next/{static/chunks/2zf4jmz9l3li2.js → standalone/.next/static/chunks/2w-y83mjlpnse.js} +1 -1
- package/.next/standalone/.next/static/chunks/2ws1xf293j-tm.js +5 -0
- package/.next/standalone/.next/static/chunks/3cqn-r-y5rrw1.js +5 -0
- package/.next/standalone/.next/static/chunks/3opgg1efrx8q6.js +1 -0
- package/.next/standalone/.next/static/chunks/3p51fpxxi4d5y.js +34 -0
- package/.next/{static/chunks/0an_b6zi1r_qq.js → standalone/.next/static/chunks/3y40z6of3r9py.js} +1 -5
- package/.next/standalone/.next/static/chunks/403dpflln8ah5.js +1 -0
- package/.next/standalone/CHANGELOG.md +83 -0
- package/.next/standalone/README.md +40 -14
- package/.next/standalone/SECURITY.md +17 -4
- package/.next/standalone/app/api/outreach/route.js +13 -73
- package/.next/standalone/app/api/scraper/route.js +106 -5
- package/.next/standalone/app/components/AppHeader.js +22 -6
- package/.next/standalone/app/components/AppTabs.js +4 -0
- package/.next/standalone/app/components/AutoConnect.js +286 -0
- package/.next/standalone/app/components/ChainView.js +75 -2
- package/.next/standalone/app/components/FilterPanel.js +8 -1
- package/.next/standalone/app/components/LinkedInLimits.js +38 -13
- package/.next/standalone/app/components/OutlinkQuest.js +32 -11
- package/.next/standalone/app/components/ScanStatusBar.js +18 -3
- package/.next/standalone/app/components/ScanTrail.js +13 -3
- package/.next/standalone/app/components/SeparationView.js +6 -22
- package/.next/standalone/app/components/Sidebar.js +147 -38
- package/.next/standalone/app/components/insights/Boards.js +275 -0
- package/.next/standalone/app/components/insights/PeopleView.js +266 -0
- package/.next/standalone/app/components/insights/Rail.js +156 -0
- package/.next/standalone/app/components/insights/Report.js +382 -0
- package/.next/standalone/app/components/insights/parts.js +239 -0
- package/.next/standalone/app/components/settings/UsageSection.js +50 -3
- package/.next/standalone/app/globals.css +2 -3
- package/.next/standalone/app/insights/page.js +220 -0
- package/.next/standalone/app/page.js +1 -17
- package/.next/standalone/app/queue/page.js +30 -18
- package/.next/standalone/app/setup/page.js +71 -13
- package/.next/standalone/install.sh +7 -6
- package/.next/standalone/lib/auto-connect.js +145 -0
- package/.next/standalone/lib/companies.js +1 -1
- package/.next/standalone/lib/in-progress.js +46 -0
- package/.next/standalone/lib/insights-board.js +613 -0
- package/.next/standalone/lib/linkedin-limits.js +36 -11
- package/.next/standalone/lib/requests-client.js +10 -0
- package/.next/standalone/lib/requests.js +124 -0
- package/.next/standalone/lib/scan-state.js +1 -0
- package/.next/standalone/lib/scanner-setup.js +82 -3
- package/.next/standalone/lib/scraper-client.js +18 -5
- package/.next/standalone/lib/settings.js +6 -0
- package/.next/standalone/lib/usage.js +5 -0
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/scripts/build-app.mjs +167 -11
- package/.next/standalone/scripts/build-desktop.mjs +3 -2
- package/.next/standalone/scripts/ci-mac-signing.sh +128 -0
- package/.next/standalone/scripts/entitlements/electron.plist +23 -0
- package/.next/standalone/scripts/entitlements/node.plist +27 -0
- package/.next/standalone/scripts/mac-sign.mjs +563 -0
- package/.next/standalone/scripts/make-dmg-background.mjs +2 -1
- package/.next/standalone/scripts/scrape.py +569 -9
- package/.next/standalone/scripts/set-signing-secrets.sh +96 -0
- package/.next/static/chunks/02wnf8dkxegxg.js +34 -0
- package/.next/static/chunks/0hggugbh84m4t.js +21 -0
- package/.next/{standalone/.next/static/chunks/2eo9pqq9gay3r.js → static/chunks/0ka4prpk3w9wn.js} +4 -4
- package/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
- package/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
- package/.next/{standalone/.next/static/chunks/44yn0tcd9dfk3.js → static/chunks/1bkt_hhjzvbh8.js} +1 -1
- package/.next/static/chunks/1cmphb3kh2ers.css +3 -0
- package/.next/{standalone/.next/static/chunks/1qbjermbf68xj.js → static/chunks/1d8yv3k_atka7.js} +1 -1
- package/.next/static/chunks/1ods5h86raivz.js +1 -0
- package/.next/static/chunks/23hc51oa4vkhc.js +5 -0
- package/.next/static/chunks/27n8k9wxlz5-7.js +1 -0
- package/.next/static/chunks/{0p3g5tfostsep.js → 2q9i7pcxcnph1.js} +2 -2
- package/.next/{standalone/.next/static/chunks/2zf4jmz9l3li2.js → static/chunks/2w-y83mjlpnse.js} +1 -1
- package/.next/static/chunks/2ws1xf293j-tm.js +5 -0
- package/.next/static/chunks/3cqn-r-y5rrw1.js +5 -0
- package/.next/static/chunks/3opgg1efrx8q6.js +1 -0
- package/.next/static/chunks/3p51fpxxi4d5y.js +34 -0
- package/.next/{standalone/.next/static/chunks/0an_b6zi1r_qq.js → static/chunks/3y40z6of3r9py.js} +1 -5
- package/.next/static/chunks/403dpflln8ah5.js +1 -0
- package/CHANGELOG.md +83 -0
- package/README.md +40 -14
- package/SECURITY.md +17 -4
- package/lib/auto-connect.js +145 -0
- package/lib/companies.js +1 -1
- package/lib/in-progress.js +46 -0
- package/lib/insights-board.js +613 -0
- package/lib/linkedin-limits.js +36 -11
- package/lib/requests-client.js +10 -0
- package/lib/requests.js +124 -0
- package/lib/scan-state.js +1 -0
- package/lib/scanner-setup.js +82 -3
- package/lib/scraper-client.js +18 -5
- package/lib/settings.js +6 -0
- package/lib/usage.js +5 -0
- package/package.json +1 -1
- package/scripts/scrape.py +569 -9
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_4y8z7._.js +0 -8
- package/.next/standalone/.next/server/chunks/_02twlca._.js +0 -10
- package/.next/standalone/.next/server/chunks/lib_rpc_0nef_n7.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_0plrzra.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_13a4m0c.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1if17c-.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1j-zw7v.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1sngt-q.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1v2sgme.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1vh-tgx.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_rpc_1zaubz7.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_02sband._.js +0 -7
- package/.next/standalone/.next/server/chunks/ssr/_189g8lg._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1f_n00p._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_components_0t908t-._.js +0 -3
- package/.next/standalone/.next/static/chunks/0e3g0sil79cus.js +0 -21
- package/.next/standalone/.next/static/chunks/0zd0t7e60bn4z.js +0 -1
- package/.next/standalone/.next/static/chunks/163b-20vwa06i.js +0 -34
- package/.next/standalone/.next/static/chunks/1pa-2v1ajvrko.js +0 -1
- package/.next/standalone/.next/static/chunks/23_1z47al92nz.js +0 -57
- package/.next/standalone/.next/static/chunks/260bomtr214m8.js +0 -34
- package/.next/standalone/.next/static/chunks/2xk2ra4piiuod.js +0 -34
- package/.next/standalone/.next/static/chunks/3b0-14cxqsprt.js +0 -1
- package/.next/standalone/.next/static/chunks/3jarus1_38s2z.js +0 -1
- package/.next/standalone/.next/static/chunks/3ssu341hav_sq.css +0 -3
- package/.next/standalone/.next/static/chunks/3v1qd3sqhqn0d.js +0 -1
- package/.next/static/chunks/0e3g0sil79cus.js +0 -21
- package/.next/static/chunks/0zd0t7e60bn4z.js +0 -1
- package/.next/static/chunks/163b-20vwa06i.js +0 -34
- package/.next/static/chunks/1pa-2v1ajvrko.js +0 -1
- package/.next/static/chunks/23_1z47al92nz.js +0 -57
- package/.next/static/chunks/260bomtr214m8.js +0 -34
- package/.next/static/chunks/2xk2ra4piiuod.js +0 -34
- package/.next/static/chunks/3b0-14cxqsprt.js +0 -1
- package/.next/static/chunks/3jarus1_38s2z.js +0 -1
- package/.next/static/chunks/3ssu341hav_sq.css +0 -3
- package/.next/static/chunks/3v1qd3sqhqn0d.js +0 -1
- /package/.next/standalone/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_ssgManifest.js +0 -0
- /package/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_buildManifest.js +0 -0
- /package/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_ssgManifest.js +0 -0
|
@@ -21,10 +21,15 @@
|
|
|
21
21
|
// Chromium instead would make the scanner MORE detectable, not less, which
|
|
22
22
|
// defeats the point of driving the user's real browser.
|
|
23
23
|
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
24
|
+
// Signing (DESKTOP.md D4, scripts/mac-sign.mjs). With a Developer ID identity
|
|
25
|
+
// in SIX_DEGREES_SIGN_IDENTITY, every program and library is signed inside out
|
|
26
|
+
// with the hardened runtime, and with SIX_DEGREES_NOTARY_KEY, _KEY_ID and
|
|
27
|
+
// _ISSUER the app and the disk image are notarized by Apple and stapled: it
|
|
28
|
+
// opens like any Mac app. Releases do this (release.yml). Without an identity
|
|
29
|
+
// (forks, pull requests, a local build) the app is signed ad hoc, exactly as
|
|
30
|
+
// before D4: it costs nothing and avoids the separate "app is damaged" failure
|
|
31
|
+
// that unsigned arm64 binaries otherwise hit, and a copy downloaded in a
|
|
32
|
+
// browser then needs one approval in System Settings.
|
|
28
33
|
|
|
29
34
|
import { execFileSync } from 'node:child_process';
|
|
30
35
|
import { createHash } from 'node:crypto';
|
|
@@ -38,6 +43,9 @@ import { fileURLToPath } from 'node:url';
|
|
|
38
43
|
import {
|
|
39
44
|
standaloneBuild, downloadVerified, machoSlices, machoSlice, megabytes, IMPORTS,
|
|
40
45
|
} from '../lib/scanner-python.js';
|
|
46
|
+
import {
|
|
47
|
+
signingSetup, signDeveloperId, signatureInfo, signerName, signImage, notarize, staple, stapleValid, assess, SigningError,
|
|
48
|
+
} from './mac-sign.mjs';
|
|
41
49
|
|
|
42
50
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
43
51
|
const pkg = JSON.parse(readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
|
|
@@ -53,6 +61,16 @@ if (!['classic', 'electron'].includes(SHELL)) {
|
|
|
53
61
|
console.error(`\n ✗ --shell must be classic or electron, not ${SHELL}\n`);
|
|
54
62
|
process.exit(1);
|
|
55
63
|
}
|
|
64
|
+
// How this build is signed: ad hoc, or Developer ID (and notarized) when the
|
|
65
|
+
// environment names an identity (scripts/mac-sign.mjs). A setting that can't be
|
|
66
|
+
// right stops the build here, before anything is built.
|
|
67
|
+
const SIGNING = signingSetup(process.env, { exists: existsSync });
|
|
68
|
+
if (SIGNING.error) {
|
|
69
|
+
console.error(`\n ✗ ${SIGNING.error}\n`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
const DEVELOPER_ID = SIGNING.mode === 'developer-id';
|
|
73
|
+
const NOTARIZE = Boolean(DEVELOPER_ID && SIGNING.notary);
|
|
56
74
|
const APP_NAME = 'Six Degrees';
|
|
57
75
|
const OUT = path.join(ROOT, 'dist');
|
|
58
76
|
const APP = path.join(OUT, `${APP_NAME}.app`);
|
|
@@ -115,6 +133,9 @@ function detach(mountPoint, device) {
|
|
|
115
133
|
rmSync(OUT, { recursive: true, force: true });
|
|
116
134
|
|
|
117
135
|
step('Building the app');
|
|
136
|
+
console.log(DEVELOPER_ID
|
|
137
|
+
? ` it will be signed with Developer ID${NOTARIZE ? ' and notarized by Apple' : ', not notarized (no SIX_DEGREES_NOTARY_* settings)'}`
|
|
138
|
+
: ' it will be signed ad hoc (no SIX_DEGREES_SIGN_IDENTITY)');
|
|
118
139
|
if (process.argv.includes('--fast') && existsSync(path.join(ROOT, '.next', 'standalone', 'server.js'))) {
|
|
119
140
|
console.log(' --fast: reusing the existing build (make sure it is current)');
|
|
120
141
|
} else {
|
|
@@ -290,7 +311,10 @@ writeFileSync(path.join(APP, 'Contents', 'Info.plist'), `<?xml version="1.0" enc
|
|
|
290
311
|
</plist>
|
|
291
312
|
`);
|
|
292
313
|
|
|
293
|
-
// ---- 4. sign
|
|
314
|
+
// ---- 4. sign ---------------------------------------------------------------
|
|
315
|
+
if (DEVELOPER_ID) {
|
|
316
|
+
signWithDeveloperId(APP);
|
|
317
|
+
} else {
|
|
294
318
|
step('Signing (ad-hoc)');
|
|
295
319
|
try {
|
|
296
320
|
run('codesign', ['--force', '--deep', '--sign', '-', APP]);
|
|
@@ -298,6 +322,7 @@ try {
|
|
|
298
322
|
} catch {
|
|
299
323
|
console.log(' codesign failed; the app will still run after the one-time approval');
|
|
300
324
|
}
|
|
325
|
+
}
|
|
301
326
|
} // end of the classic shell
|
|
302
327
|
|
|
303
328
|
// ---- the Electron shell (--shell=electron) -----------------------------------
|
|
@@ -348,6 +373,10 @@ async function buildElectronShell() {
|
|
|
348
373
|
// and nothing copies them again (TRAPS §37).
|
|
349
374
|
await bundlePython(path.join(APP, 'Contents', 'Resources'));
|
|
350
375
|
|
|
376
|
+
if (DEVELOPER_ID) {
|
|
377
|
+
signWithDeveloperId(APP);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
351
380
|
step('Signing (ad-hoc)');
|
|
352
381
|
// Electron's framework and helpers must all carry the same kind of signature,
|
|
353
382
|
// or macOS refuses to load them; re-signing the whole bundle ad hoc does that.
|
|
@@ -359,6 +388,96 @@ async function buildElectronShell() {
|
|
|
359
388
|
console.log(' signed ad-hoc and verified — no Apple account needed, still unnotarised');
|
|
360
389
|
}
|
|
361
390
|
|
|
391
|
+
// ---- Developer ID and notarization (DESKTOP.md D4) ----------------------------
|
|
392
|
+
// Inside out with the hardened runtime (scripts/mac-sign.mjs signDeveloperId:
|
|
393
|
+
// every loose program and library, then the helper apps and frameworks deepest
|
|
394
|
+
// first, then the app), then the signed programs are run once to prove their
|
|
395
|
+
// entitlements are enough. With the notary settings, the app goes to Apple and
|
|
396
|
+
// comes back with its ticket stapled to it, and only then is the disk image made
|
|
397
|
+
// from it: the app people drag to Applications carries its own ticket, and so
|
|
398
|
+
// does the copy install.sh and the in-app updater put in place with ditto.
|
|
399
|
+
function signWithDeveloperId(app) {
|
|
400
|
+
step('Signing with Developer ID (inside out, hardened runtime, timestamped)');
|
|
401
|
+
const { info } = guard(() => signDeveloperId(app, SIGNING));
|
|
402
|
+
checkSignedRuntime(app, info);
|
|
403
|
+
if (!NOTARIZE) return;
|
|
404
|
+
step('Notarizing the app (Apple; usually a few minutes)');
|
|
405
|
+
const zip = path.join(OUT, 'notarize-app.zip');
|
|
406
|
+
run('ditto', ['-c', '-k', '--sequesterRsrc', '--keepParent', app, zip]);
|
|
407
|
+
guard(() => notarize(zip, SIGNING.notary, { what: 'the app' }));
|
|
408
|
+
rmSync(zip, { force: true });
|
|
409
|
+
guard(() => staple(app));
|
|
410
|
+
const verdict = assess(app, 'exec');
|
|
411
|
+
if (!verdict.ok && !verdict.disabled) fail(`Gatekeeper doesn't accept the stapled app as notarized: ${oneLine(verdict.text)}`);
|
|
412
|
+
console.log(verdict.ok ? ` stapled; Gatekeeper says: ${verdict.source}` : gatekeeperOff());
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// The signed programs, run as the app runs them: the server's Node (and sharp,
|
|
416
|
+
// the one native module it loads), the scanner's Python with its packages, and
|
|
417
|
+
// Playwright's driver. A missing entitlement or a library that fails library
|
|
418
|
+
// validation stops the build here, minutes before notarization would, and long
|
|
419
|
+
// before a user's scan. Nothing here writes into the app (no bytecode: -B and
|
|
420
|
+
// PYTHONDONTWRITEBYTECODE), which the image check would catch anyway.
|
|
421
|
+
function checkSignedRuntime(app, info) {
|
|
422
|
+
step('Running the signed programs under the hardened runtime');
|
|
423
|
+
if (!info.team) {
|
|
424
|
+
// A self-signed test identity has no Team ID, and library validation then
|
|
425
|
+
// refuses even the app's own libraries. A Developer ID always has one.
|
|
426
|
+
console.log(' skipped: this identity has no Team ID (a test identity, not a Developer ID)');
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
const res = path.join(app, 'Contents', 'Resources');
|
|
430
|
+
const env = {
|
|
431
|
+
HOME: os.homedir(), TMPDIR: os.tmpdir(), PATH: '/usr/bin:/bin:/usr/sbin:/sbin', LANG: 'en_US.UTF-8',
|
|
432
|
+
PYTHONNOUSERSITE: '1', PYTHONDONTWRITEBYTECODE: '1',
|
|
433
|
+
};
|
|
434
|
+
const server = [path.join(res, 'server'), path.join(res, 'app')].find((d) => existsSync(path.join(d, 'server.js')));
|
|
435
|
+
const sharp = server && existsSync(path.join(server, 'node_modules', 'sharp')) ? path.join(server, 'node_modules', 'sharp') : null;
|
|
436
|
+
console.log(` the server's Node: ${mustRun(path.join(res, 'node'), ['-e',
|
|
437
|
+
`require('node:sqlite');${sharp ? ` require(${JSON.stringify(sharp)});` : ''} console.log(process.version${sharp ? ", '· sharp loads'" : ''})`],
|
|
438
|
+
env, 'The app\'s Node doesn\'t run once signed (its entitlements: scripts/entitlements/node.plist)')}`);
|
|
439
|
+
const py = path.join(res, 'python');
|
|
440
|
+
if (!existsSync(path.join(py, 'bin', 'python3'))) return;
|
|
441
|
+
console.log(` the scanner's Python: ${mustRun(path.join(py, 'bin', 'python3'), ['-E', '-s', '-B', '-c',
|
|
442
|
+
`${IMPORTS}; import sys; print(sys.version.split()[0], "· its packages load")`],
|
|
443
|
+
env, 'The scanner\'s Python doesn\'t run once signed')}`);
|
|
444
|
+
const xy = readdirSync(path.join(py, 'lib')).find((n) => /^python3\.\d+$/.test(n));
|
|
445
|
+
const driver = path.join(py, 'lib', xy || 'python3', 'site-packages', 'playwright', 'driver');
|
|
446
|
+
if (existsSync(path.join(driver, 'node'))) {
|
|
447
|
+
console.log(` Playwright's driver: ${mustRun(path.join(driver, 'node'), [path.join(driver, 'package', 'cli.js'), '--version'],
|
|
448
|
+
env, 'Playwright\'s driver doesn\'t start once signed')}`);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// A step of the signing that failed: its reason, never a credential (mac-sign.mjs
|
|
453
|
+
// never puts one in a message), and the build stops.
|
|
454
|
+
function guard(fn) {
|
|
455
|
+
try {
|
|
456
|
+
return fn();
|
|
457
|
+
} catch (err) {
|
|
458
|
+
fail(err instanceof SigningError ? err.message : `Signing failed: ${String(err.message || err).split('\n')[0]}`);
|
|
459
|
+
}
|
|
460
|
+
return undefined;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function fail(message) {
|
|
464
|
+
console.error(`\n ✗ ${message}\n`);
|
|
465
|
+
process.exit(1);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// When this machine has Gatekeeper's assessments turned off, spctl accepts
|
|
469
|
+
// anything and can't confirm notarization; Apple's "Accepted" and the stapled
|
|
470
|
+
// tickets (validated) are what's left, and the log says so.
|
|
471
|
+
function gatekeeperOff() {
|
|
472
|
+
return ' stapled; Gatekeeper\'s assessments are turned off on this machine, so it can\'t be asked: '
|
|
473
|
+
+ 'the stapled tickets and Apple\'s Accepted are the check';
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// (Function declarations, not consts: the shells call these before this line runs.)
|
|
477
|
+
function oneLine(text) {
|
|
478
|
+
return String(text || '').trim().split('\n').join(' | ');
|
|
479
|
+
}
|
|
480
|
+
|
|
362
481
|
// ---- the scanner's Python (Electron app only; DESKTOP.md D2) ------------------
|
|
363
482
|
// A standalone CPython from python-build-standalone, with the scanner's packages
|
|
364
483
|
// installed, at Contents/Resources/python. desktop/main.mjs names it to the
|
|
@@ -602,9 +721,11 @@ mkdirSync(staging, { recursive: true });
|
|
|
602
721
|
// on the build machine: anywhere else those paths do not exist (TRAPS §37).
|
|
603
722
|
run('ditto', [APP, path.join(staging, `${APP_NAME}.app`)]);
|
|
604
723
|
|
|
605
|
-
// The picture behind the window says what to do: drag across,
|
|
606
|
-
//
|
|
607
|
-
// this image used to carry.
|
|
724
|
+
// The picture behind the window says what to do: drag across, and that the app
|
|
725
|
+
// is signed and notarized, so it opens like any Mac app (it said Open Anyway
|
|
726
|
+
// until D4). It replaces the READ ME text file this image used to carry. A build
|
|
727
|
+
// signed ad hoc gets the same picture: it never left this Mac, so macOS doesn't
|
|
728
|
+
// ask about it either. Made by scripts/make-dmg-background.mjs from
|
|
608
729
|
// scripts/dmg/background.html; its geometry and the positions below are one
|
|
609
730
|
// layout, so change them together.
|
|
610
731
|
const BACKGROUND = path.join(ROOT, 'scripts', 'dmg', 'background.tiff');
|
|
@@ -742,6 +863,21 @@ detach(mount, device);
|
|
|
742
863
|
run('hdiutil', ['convert', rw, '-format', 'UDZO', '-imagekey', 'zlib-level=9', '-o', dmg, '-ov']);
|
|
743
864
|
rmSync(rw, { force: true });
|
|
744
865
|
rmSync(staging, { recursive: true, force: true });
|
|
866
|
+
|
|
867
|
+
// The image gets its own signature and ticket (DESKTOP.md D4): Gatekeeper judges
|
|
868
|
+
// a downloaded .dmg by them before it looks at the app inside. Made from the
|
|
869
|
+
// stapled app, so the app keeps its own ticket once it is copied out.
|
|
870
|
+
if (DEVELOPER_ID) {
|
|
871
|
+
step('Signing the disk image');
|
|
872
|
+
guard(() => signImage(dmg, SIGNING));
|
|
873
|
+
console.log(' signed and verified');
|
|
874
|
+
if (NOTARIZE) {
|
|
875
|
+
step('Notarizing the disk image (Apple; usually a few minutes)');
|
|
876
|
+
guard(() => notarize(dmg, SIGNING.notary, { what: 'the disk image' }));
|
|
877
|
+
guard(() => staple(dmg));
|
|
878
|
+
console.log(' stapled');
|
|
879
|
+
}
|
|
880
|
+
}
|
|
745
881
|
checkImage(dmg);
|
|
746
882
|
|
|
747
883
|
// Check the app as people will get it: inside the finished image, not the copy
|
|
@@ -763,6 +899,12 @@ function checkImage(image) {
|
|
|
763
899
|
} catch (err) {
|
|
764
900
|
problem = `its signature does not verify: ${(err.stderr || '').toString().trim().split('\n').slice(0, 2).join(' ')}`;
|
|
765
901
|
}
|
|
902
|
+
// Notarized: the app inside carries its ticket, and Gatekeeper accepts it.
|
|
903
|
+
if (NOTARIZE && !problem) {
|
|
904
|
+
const verdict = assess(inside, 'exec');
|
|
905
|
+
if (!stapleValid(inside)) problem = 'it has no valid stapled notarization ticket';
|
|
906
|
+
else if (!verdict.ok && !verdict.disabled) problem = `Gatekeeper doesn't accept it as notarized (${oneLine(verdict.text)})`;
|
|
907
|
+
}
|
|
766
908
|
const escaping = execFileSync('find', [inside, '-type', 'l'])
|
|
767
909
|
.toString().split('\n').filter(Boolean)
|
|
768
910
|
.filter((link) => {
|
|
@@ -778,10 +920,24 @@ function checkImage(image) {
|
|
|
778
920
|
console.error(`\n ✗ The app inside ${path.basename(image)} is broken: ${problem}\n`);
|
|
779
921
|
process.exit(1);
|
|
780
922
|
}
|
|
781
|
-
|
|
923
|
+
// And the image itself, as Gatekeeper judges a downloaded one: by its own
|
|
924
|
+
// signature (context:primary-signature) and its own ticket.
|
|
925
|
+
if (NOTARIZE) {
|
|
926
|
+
const verdict = assess(image, 'open');
|
|
927
|
+
if (!stapleValid(image)) fail(`${path.basename(image)} has no valid stapled notarization ticket.`);
|
|
928
|
+
if (!verdict.ok && !verdict.disabled) fail(`Gatekeeper doesn't accept ${path.basename(image)} as notarized: ${oneLine(verdict.text)}`);
|
|
929
|
+
if (verdict.disabled) console.log(gatekeeperOff());
|
|
930
|
+
}
|
|
931
|
+
console.log(` signature verifies, and every link stays inside the app${NOTARIZE ? '; the app and the image are notarized and stapled, and Gatekeeper accepts both' : ''}`);
|
|
782
932
|
}
|
|
783
933
|
|
|
784
934
|
const size = execFileSync('du', ['-h', dmg]).toString().split('\t')[0];
|
|
785
935
|
console.log(`\n✓ ${dmg} (${size})\n`);
|
|
786
|
-
|
|
787
|
-
|
|
936
|
+
if (DEVELOPER_ID) {
|
|
937
|
+
const who = signerName(signatureInfo(APP).authority) || 'this Developer ID';
|
|
938
|
+
if (NOTARIZE) console.log(` Signed by ${who} and notarized by Apple: it opens like any Mac app.\n`);
|
|
939
|
+
else console.log(` Signed by ${who}, not notarized: a copy downloaded in a browser still needs one approval\n in System Settings > Privacy & Security.\n`);
|
|
940
|
+
} else {
|
|
941
|
+
console.log(' Signed ad hoc (no Developer ID here: SIX_DEGREES_SIGN_IDENTITY). A copy downloaded in a browser');
|
|
942
|
+
console.log(' needs one approval in System Settings > Privacy & Security.\n');
|
|
943
|
+
}
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
// Menu and Desktop shortcuts. No admin rights asked for.
|
|
15
15
|
// Linux @electron/packager, then a .deb (chrome-sandbox setuid root, which
|
|
16
16
|
// Electron needs on Ubuntu 24.04 and later) and a plain .tar.gz.
|
|
17
|
-
// Unsigned
|
|
18
|
-
// Run anyway" the
|
|
17
|
+
// Unsigned (the Mac app is signed and notarized since D4; Windows signing is
|
|
18
|
+
// D4's other half): Windows shows SmartScreen's "More info → Run anyway" the
|
|
19
|
+
// first time.
|
|
19
20
|
//
|
|
20
21
|
// Built on the platform it is for (release.yml has a job each): pip installs
|
|
21
22
|
// the Python's packages by running that Python. No new npm dependency: packager
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# The Mac release's Developer ID, for .github/workflows/release.yml's Mac jobs
|
|
3
|
+
# (docs/brain/DESKTOP.md D4). Two commands:
|
|
4
|
+
#
|
|
5
|
+
# ci-mac-signing.sh setup VERSION DRY_RUN before the build
|
|
6
|
+
# ci-mac-signing.sh cleanup after it, always (if: always())
|
|
7
|
+
#
|
|
8
|
+
# setup asks scripts/mac-sign.mjs whether this release signs (release-plan):
|
|
9
|
+
# - all five secrets set: it signs, dry run or not;
|
|
10
|
+
# - none set: ad hoc, as before 1.0, unless this is a real release of 1.0.0 or
|
|
11
|
+
# later, which must be signed: then it fails here, before anything is built;
|
|
12
|
+
# - some but not all: always a mistake, and it fails, naming the missing ones.
|
|
13
|
+
# When it signs, it decodes the certificate (.p12, which carries Apple's
|
|
14
|
+
# Developer ID G2 intermediate too) into a temporary keychain with a random
|
|
15
|
+
# password, finds the "Developer ID Application" identity in it, decodes the App
|
|
16
|
+
# Store Connect API key (.p8) for notarytool, and hands the build their places
|
|
17
|
+
# through $GITHUB_ENV: SIX_DEGREES_SIGN_IDENTITY (the identity's SHA-1: names
|
|
18
|
+
# can repeat across renewals, a hash can't), SIX_DEGREES_SIGN_KEYCHAIN and
|
|
19
|
+
# SIX_DEGREES_NOTARY_KEY. The key's id and issuer reach the build step straight
|
|
20
|
+
# from the secrets (release.yml), never through a file. MAC_SIGNING says which
|
|
21
|
+
# it was (developer-id or ad-hoc), for the smoke test and the release notes.
|
|
22
|
+
#
|
|
23
|
+
# The secrets arrive as environment variables, set by release.yml from GitHub's
|
|
24
|
+
# secrets and nowhere else. Nothing here prints one: values go to files made
|
|
25
|
+
# under umask 077, or to `security` itself, and GitHub masks them in the log
|
|
26
|
+
# besides. Never run this with `bash -x`. cleanup deletes the keychain, puts the
|
|
27
|
+
# keychain search list back as it was, and removes every decoded file.
|
|
28
|
+
|
|
29
|
+
set -euo pipefail
|
|
30
|
+
|
|
31
|
+
work="${RUNNER_TEMP:?RUNNER_TEMP is not set (this runs in GitHub Actions)}/six-degrees-signing"
|
|
32
|
+
keychain="$work/signing.keychain-db"
|
|
33
|
+
here="$(cd "$(dirname "$0")" && pwd)"
|
|
34
|
+
|
|
35
|
+
say() { printf '%s\n' "$*"; }
|
|
36
|
+
die() { printf '::error::%s\n' "$*"; exit 1; }
|
|
37
|
+
|
|
38
|
+
setup() {
|
|
39
|
+
local version="${1:?usage: ci-mac-signing.sh setup VERSION DRY_RUN}" dry_run="${2:-false}" plan
|
|
40
|
+
local genv="${GITHUB_ENV:?GITHUB_ENV is not set}"
|
|
41
|
+
# release-plan reads only whether each secret is set, never a value.
|
|
42
|
+
if ! plan="$(node "$here/mac-sign.mjs" release-plan "$version" "$dry_run")"; then
|
|
43
|
+
die "The Mac app can't be built as asked: see the line above."
|
|
44
|
+
fi
|
|
45
|
+
if [ "$plan" != developer-id ]; then
|
|
46
|
+
echo "MAC_SIGNING=ad-hoc" >> "$genv"
|
|
47
|
+
say "Signing: ad hoc."
|
|
48
|
+
return 0
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
umask 077
|
|
52
|
+
rm -rf "$work"
|
|
53
|
+
mkdir -p "$work"
|
|
54
|
+
|
|
55
|
+
# The certificate, for the keychain only; its file goes as soon as it's in.
|
|
56
|
+
printf '%s' "$MACOS_SIGN_P12_BASE64" | base64 --decode > "$work/cert.p12" 2>/dev/null \
|
|
57
|
+
|| die "MACOS_SIGN_P12_BASE64 isn't base64 (set it again with scripts/set-signing-secrets.sh)."
|
|
58
|
+
[ -s "$work/cert.p12" ] || die "MACOS_SIGN_P12_BASE64 decodes to nothing."
|
|
59
|
+
# The API key, for notarytool, kept until cleanup.
|
|
60
|
+
printf '%s' "$APPLE_API_KEY_P8_BASE64" | base64 --decode > "$work/AuthKey.p8" 2>/dev/null \
|
|
61
|
+
|| die "APPLE_API_KEY_P8_BASE64 isn't base64 (set it again with scripts/set-signing-secrets.sh)."
|
|
62
|
+
grep -q -- '-----BEGIN PRIVATE KEY-----' "$work/AuthKey.p8" \
|
|
63
|
+
|| die "APPLE_API_KEY_P8_BASE64 doesn't decode to an App Store Connect API key (.p8)."
|
|
64
|
+
|
|
65
|
+
# A keychain of its own, with a password nobody needs to know, unlocked for
|
|
66
|
+
# the length of the job (6 hours), and codesign allowed to use the key without
|
|
67
|
+
# asking (the partition list): there is nobody to click Allow on a runner.
|
|
68
|
+
local kc_pass
|
|
69
|
+
kc_pass="$(head -c 32 /dev/urandom | base64 | tr -d '\n=+/')"
|
|
70
|
+
security create-keychain -p "$kc_pass" "$keychain"
|
|
71
|
+
security set-keychain-settings -lut 21600 "$keychain"
|
|
72
|
+
security unlock-keychain -p "$kc_pass" "$keychain"
|
|
73
|
+
security import "$work/cert.p12" -k "$keychain" -f pkcs12 -P "$MACOS_SIGN_P12_PASSWORD" \
|
|
74
|
+
-T /usr/bin/codesign -T /usr/bin/security > /dev/null \
|
|
75
|
+
|| die "The certificate wouldn't import: is MACOS_SIGN_P12_PASSWORD the .p12's password?"
|
|
76
|
+
rm -f "$work/cert.p12"
|
|
77
|
+
security set-key-partition-list -S apple-tool:,apple: -s -k "$kc_pass" "$keychain" > /dev/null
|
|
78
|
+
kc_pass=""
|
|
79
|
+
|
|
80
|
+
# codesign finds an identity only in a keychain on the search list. The list as
|
|
81
|
+
# it was is kept, for cleanup to put back.
|
|
82
|
+
security list-keychains -d user > "$work/search-list"
|
|
83
|
+
local line orig=()
|
|
84
|
+
while IFS= read -r line; do
|
|
85
|
+
line="${line#"${line%%[![:space:]]*}"}"; line="${line%\"}"; line="${line#\"}"
|
|
86
|
+
[ -n "$line" ] && orig+=("$line")
|
|
87
|
+
done < "$work/search-list"
|
|
88
|
+
security list-keychains -d user -s "$keychain" ${orig[@]+"${orig[@]}"}
|
|
89
|
+
|
|
90
|
+
# By its kind, not its full name: whatever Developer ID Application identity
|
|
91
|
+
# the certificate holds, and it must be valid (its chain reaches Apple's root).
|
|
92
|
+
local found identity name
|
|
93
|
+
found="$(security find-identity -v -p codesigning "$keychain" | grep '"Developer ID Application: ' | head -1 || true)"
|
|
94
|
+
identity="$(printf '%s\n' "$found" | awk '{print $2}')"
|
|
95
|
+
name="$(printf '%s\n' "$found" | sed -n 's/.*"\(Developer ID Application: [^"]*\)".*/\1/p')"
|
|
96
|
+
if [ -z "$identity" ]; then
|
|
97
|
+
say "The keychain holds these code-signing identities (valid or not):"
|
|
98
|
+
security find-identity -p codesigning "$keychain" | sed 's/^/ /'
|
|
99
|
+
die "No valid \"Developer ID Application\" identity in MACOS_SIGN_P12_BASE64. Export the Developer ID Application certificate with its private key (and Apple's intermediate) as the .p12."
|
|
100
|
+
fi
|
|
101
|
+
{
|
|
102
|
+
echo "SIX_DEGREES_SIGN_IDENTITY=$identity"
|
|
103
|
+
echo "SIX_DEGREES_SIGN_KEYCHAIN=$keychain"
|
|
104
|
+
echo "SIX_DEGREES_NOTARY_KEY=$work/AuthKey.p8"
|
|
105
|
+
echo "MAC_SIGNING=developer-id"
|
|
106
|
+
} >> "$genv"
|
|
107
|
+
say "Signing: $name, from a temporary keychain; notarized with the App Store Connect API key."
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
cleanup() {
|
|
111
|
+
if [ -f "$work/search-list" ]; then
|
|
112
|
+
local line orig=()
|
|
113
|
+
while IFS= read -r line; do
|
|
114
|
+
line="${line#"${line%%[![:space:]]*}"}"; line="${line%\"}"; line="${line#\"}"
|
|
115
|
+
[ -n "$line" ] && orig+=("$line")
|
|
116
|
+
done < "$work/search-list"
|
|
117
|
+
security list-keychains -d user -s ${orig[@]+"${orig[@]}"} || true
|
|
118
|
+
fi
|
|
119
|
+
if [ -e "$keychain" ]; then security delete-keychain "$keychain" || true; fi
|
|
120
|
+
rm -rf "$work"
|
|
121
|
+
say "Signing: cleaned up (no keychain, key or certificate left)."
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
case "${1:-}" in
|
|
125
|
+
setup) shift; setup "$@" ;;
|
|
126
|
+
cleanup) cleanup ;;
|
|
127
|
+
*) echo "usage: ci-mac-signing.sh setup VERSION DRY_RUN | cleanup" >&2; exit 2 ;;
|
|
128
|
+
esac
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<!--
|
|
4
|
+
Six Degrees.app and its Electron helper apps (GPU, Renderer, Plugin), signed
|
|
5
|
+
with Developer ID and the hardened runtime (scripts/mac-sign.mjs, DESKTOP.md D4).
|
|
6
|
+
|
|
7
|
+
allow-jit V8 compiles JavaScript as it runs; the hardened
|
|
8
|
+
runtime refuses that without it.
|
|
9
|
+
allow-unsigned-executable-memory what V8 still uses where it can't use MAP_JIT
|
|
10
|
+
(Intel Macs). Discord's and Electron's own
|
|
11
|
+
templates carry the same two.
|
|
12
|
+
|
|
13
|
+
Never disable-library-validation: every library the app loads is signed by the
|
|
14
|
+
same team in the same pass, and it loads nothing from outside itself.
|
|
15
|
+
-->
|
|
16
|
+
<plist version="1.0">
|
|
17
|
+
<dict>
|
|
18
|
+
<key>com.apple.security.cs.allow-jit</key>
|
|
19
|
+
<true/>
|
|
20
|
+
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
|
21
|
+
<true/>
|
|
22
|
+
</dict>
|
|
23
|
+
</plist>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<!--
|
|
4
|
+
The Node inside the app (Contents/Resources/node), which runs the server, and
|
|
5
|
+
Playwright's driver's Node when it isn't a link to that one. Signed with
|
|
6
|
+
Developer ID and the hardened runtime (scripts/mac-sign.mjs, DESKTOP.md D4).
|
|
7
|
+
|
|
8
|
+
allow-jit V8 compiles JavaScript as it runs. Without it
|
|
9
|
+
Node 24 stops before running anything: "Failed
|
|
10
|
+
to reserve virtual memory for CodeRange"
|
|
11
|
+
(checked on this build's Node, 2026-10-04).
|
|
12
|
+
allow-unsigned-executable-memory what V8 still uses where it can't use MAP_JIT
|
|
13
|
+
(Intel Macs). Node's own release signature
|
|
14
|
+
carries both.
|
|
15
|
+
|
|
16
|
+
Never disable-library-validation, which Node's own signature does carry so that
|
|
17
|
+
anyone's native addons load: the only native code this server loads is the
|
|
18
|
+
app's own (sharp and its libvips), signed by the same team in the same pass.
|
|
19
|
+
-->
|
|
20
|
+
<plist version="1.0">
|
|
21
|
+
<dict>
|
|
22
|
+
<key>com.apple.security.cs.allow-jit</key>
|
|
23
|
+
<true/>
|
|
24
|
+
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
|
25
|
+
<true/>
|
|
26
|
+
</dict>
|
|
27
|
+
</plist>
|