Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3402099
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/keyserver/icons/safari-pinned-tab.svg b/keyserver/icons/safari-pinned-tab.svg
deleted file mode 100644
index f3d8b0b5f..000000000
--- a/keyserver/icons/safari-pinned-tab.svg
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
- "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
-<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
- width="1200.000000pt" height="1200.000000pt" viewBox="0 0 1200.000000 1200.000000"
- preserveAspectRatio="xMidYMid meet">
-<metadata>
-Created by potrace 1.11, written by Peter Selinger 2001-2013
-</metadata>
-<g transform="translate(0.000000,1200.000000) scale(0.100000,-0.100000)"
-fill="#000000" stroke="none">
-<path d="M2000 11400 l0 -600 -367 -1 c-203 0 -388 -2 -413 -4 -66 -5 -143
--15 -160 -20 -8 -2 -28 -6 -43 -9 -87 -15 -259 -77 -357 -130 -355 -189 -583
--496 -648 -871 -9 -54 -9 -8666 0 -8731 41 -283 218 -567 471 -755 81 -60 230
--149 251 -149 7 0 16 -4 21 -9 23 -21 173 -67 355 -108 19 -4 2204 -8 4855
--10 4898 -2 4904 -2 5012 31 10 3 31 7 47 10 101 18 324 117 441 197 282 192
-457 454 520 779 12 65 14 651 12 4415 l-2 4340 -27 92 c-15 50 -39 120 -53
-155 -27 67 -103 201 -117 206 -4 2 -8 8 -8 14 0 23 -128 161 -220 239 -150
-126 -407 252 -575 282 -191 35 -194 35 -622 36 l-373 1 0 600 0 600 -664 0
-c-522 0 -665 -3 -668 -12 -2 -7 -3 -277 -3 -600 l1 -588 -2666 0 -2666 0 0
-598 0 597 -667 3 -667 2 0 -600z m8666 -6897 l-1 -3298 -4666 -3 -4665 -2 0
-3300 0 3300 4666 0 4666 0 0 -3297z"/>
-<path d="M3585 6979 c-334 -74 -579 -373 -580 -709 0 -143 9 -196 54 -308 89
--224 324 -413 560 -450 50 -8 208 -8 256 0 198 34 359 135 482 302 98 133 145
-288 139 456 -5 134 -20 198 -72 305 -100 207 -289 355 -528 412 -58 14 -235 9
--311 -8z"/>
-<path d="M8169 6996 c-2 -2 -24 -6 -49 -9 -161 -20 -339 -128 -458 -276 -43
--53 -104 -157 -107 -181 0 -3 -3 -9 -7 -15 -3 -5 -14 -41 -24 -80 -25 -94 -24
--284 0 -375 84 -311 356 -534 678 -556 336 -23 646 183 756 502 30 87 33 106
-37 225 7 220 -70 407 -233 564 -82 80 -212 152 -327 181 -16 4 -37 9 -45 11
--23 6 -216 14 -221 9z"/>
-<path d="M7539 3723 c-64 -82 -202 -222 -289 -294 -253 -211 -605 -363 -935
--404 -27 -4 -61 -9 -75 -11 -62 -13 -451 -11 -560 2 -287 35 -544 121 -750
-253 -159 102 -337 270 -453 426 -33 44 -62 80 -66 80 -6 0 -162 -104 -401
--268 -69 -47 -189 -129 -268 -183 -79 -54 -145 -101 -147 -105 -8 -12 145
--212 250 -327 267 -293 570 -511 920 -661 88 -38 283 -107 325 -116 8 -2 44
--11 80 -20 65 -17 83 -21 130 -30 14 -2 50 -9 80 -15 175 -34 318 -45 580 -45
-191 0 327 7 424 20 383 52 687 143 981 293 39 19 84 42 100 50 50 25 306 196
-371 248 172 138 376 343 489 488 17 22 41 52 54 69 20 24 22 31 10 37 -8 5
--186 137 -395 294 -210 157 -386 286 -392 286 -6 0 -34 -30 -63 -67z"/>
-</g>
-</svg>
diff --git a/keyserver/src/responders/website-responders.js b/keyserver/src/responders/website-responders.js
index 0dc2f08ce..6585b24dd 100644
--- a/keyserver/src/responders/website-responders.js
+++ b/keyserver/src/responders/website-responders.js
@@ -1,344 +1,343 @@
// @flow
import html from 'common-tags/lib/html';
import type { $Response, $Request } from 'express';
import fs from 'fs';
import _keyBy from 'lodash/fp/keyBy';
import * as React from 'react';
import ReactDOMServer from 'react-dom/server';
import { Provider } from 'react-redux';
import { Route, StaticRouter } from 'react-router';
import { createStore, type Store } from 'redux';
import { promisify } from 'util';
import { daysToEntriesFromEntryInfos } from 'lib/reducers/entry-reducer';
import { freshMessageStore } from 'lib/reducers/message-reducer';
import { mostRecentlyReadThread } from 'lib/selectors/thread-selectors';
import { mostRecentMessageTimestamp } from 'lib/shared/message-utils';
import { threadHasPermission } from 'lib/shared/thread-utils';
import { defaultWebEnabledApps } from 'lib/types/enabled-apps';
import { defaultCalendarFilters } from 'lib/types/filter-types';
import { defaultNumberPerThread } from 'lib/types/message-types';
import { defaultEnabledReports } from 'lib/types/report-types';
import { defaultConnectionInfo } from 'lib/types/socket-types';
import { threadPermissions } from 'lib/types/thread-types';
import type { CurrentUserInfo } from 'lib/types/user-types';
import { currentDateInTimeZone } from 'lib/utils/date-utils';
import { ServerError } from 'lib/utils/errors';
import { promiseAll } from 'lib/utils/promises';
import { reducer } from 'web/redux/redux-setup';
import type { AppState, Action } from 'web/redux/redux-setup';
import getTitle from 'web/title/getTitle';
import { navInfoFromURL } from 'web/url-utils';
import { fetchEntryInfos } from '../fetchers/entry-fetchers';
import { fetchMessageInfos } from '../fetchers/message-fetchers';
import { fetchThreadInfos } from '../fetchers/thread-fetchers';
import {
fetchCurrentUserInfo,
fetchKnownUserInfos,
} from '../fetchers/user-fetchers';
import { setNewSession } from '../session/cookies';
import { Viewer } from '../session/viewer';
import { streamJSON, waitForStream } from '../utils/json-stream';
import {
getAppURLFactsFromRequestURL,
clientPathFromRouterPath,
} from '../utils/urls';
const { renderToNodeStream } = ReactDOMServer;
const access = promisify(fs.access);
const googleFontsURL =
'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&family=Inter:wght@400;500;600&display=swap';
const localFontsURL = 'fonts/local-fonts.css';
async function getFontsURL() {
try {
await access(localFontsURL);
return localFontsURL;
} catch {
return googleFontsURL;
}
}
type AssetInfo = { jsURL: string, fontsURL: string, cssInclude: string };
let assetInfo: ?AssetInfo = null;
async function getAssetInfo() {
if (assetInfo) {
return assetInfo;
}
if (process.env.NODE_ENV === 'development') {
const fontsURL = await getFontsURL();
assetInfo = {
jsURL: 'http://localhost:8080/dev.build.js',
fontsURL,
cssInclude: '',
};
return assetInfo;
}
// $FlowFixMe web/dist doesn't always exist
const { default: assets } = await import('web/dist/assets');
assetInfo = {
jsURL: `compiled/${assets.browser.js}`,
fontsURL: googleFontsURL,
cssInclude: html`
<link
rel="stylesheet"
type="text/css"
href="compiled/${assets.browser.css}"
/>
`,
};
return assetInfo;
}
let webpackCompiledRootComponent: ?React.ComponentType<{}> = null;
async function getWebpackCompiledRootComponentForSSR() {
if (webpackCompiledRootComponent) {
return webpackCompiledRootComponent;
}
try {
// $FlowFixMe web/dist doesn't always exist
const webpackBuild = await import('web/dist/app.build.cjs');
webpackCompiledRootComponent = webpackBuild.default.default;
return webpackCompiledRootComponent;
} catch {
throw new Error(
'Could not load app.build.cjs. ' +
'Did you forget to run `yarn dev` in the web folder?',
);
}
}
async function websiteResponder(
viewer: Viewer,
req: $Request,
res: $Response,
): Promise<void> {
const appURLFacts = getAppURLFactsFromRequestURL(req.originalUrl);
const { basePath, baseDomain } = appURLFacts;
const baseURL = basePath.replace(/\/$/, '');
const baseHref = baseDomain + baseURL;
const appPromise = getWebpackCompiledRootComponentForSSR();
let initialNavInfo;
try {
initialNavInfo = navInfoFromURL(req.url, {
now: currentDateInTimeZone(viewer.timeZone),
});
} catch (e) {
throw new ServerError(e.message);
}
const calendarQuery = {
startDate: initialNavInfo.startDate,
endDate: initialNavInfo.endDate,
filters: defaultCalendarFilters,
};
const messageSelectionCriteria = { joinedThreads: true };
const initialTime = Date.now();
const assetInfoPromise = getAssetInfo();
const threadInfoPromise = fetchThreadInfos(viewer);
const messageInfoPromise = fetchMessageInfos(
viewer,
messageSelectionCriteria,
defaultNumberPerThread,
);
const entryInfoPromise = fetchEntryInfos(viewer, [calendarQuery]);
const currentUserInfoPromise = fetchCurrentUserInfo(viewer);
const userInfoPromise = fetchKnownUserInfos(viewer);
const sessionIDPromise = (async () => {
if (viewer.loggedIn) {
await setNewSession(viewer, calendarQuery, initialTime);
}
return viewer.sessionID;
})();
const threadStorePromise = (async () => {
const { threadInfos } = await threadInfoPromise;
return { threadInfos };
})();
const messageStorePromise = (async () => {
const [
{ threadInfos },
{ rawMessageInfos, truncationStatuses },
] = await Promise.all([threadInfoPromise, messageInfoPromise]);
const { messageStore: freshStore } = freshMessageStore(
rawMessageInfos,
truncationStatuses,
mostRecentMessageTimestamp(rawMessageInfos, initialTime),
threadInfos,
);
return freshStore;
})();
const entryStorePromise = (async () => {
const { rawEntryInfos } = await entryInfoPromise;
return {
entryInfos: _keyBy('id')(rawEntryInfos),
daysToEntries: daysToEntriesFromEntryInfos(rawEntryInfos),
lastUserInteractionCalendar: initialTime,
};
})();
const userStorePromise = (async () => {
const userInfos = await userInfoPromise;
return { userInfos, inconsistencyReports: [] };
})();
const navInfoPromise = (async () => {
const [{ threadInfos }, messageStore] = await Promise.all([
threadInfoPromise,
messageStorePromise,
]);
const finalNavInfo = initialNavInfo;
const requestedActiveChatThreadID = finalNavInfo.activeChatThreadID;
if (
requestedActiveChatThreadID &&
!threadHasPermission(
threadInfos[requestedActiveChatThreadID],
threadPermissions.VISIBLE,
)
) {
finalNavInfo.activeChatThreadID = null;
}
if (!finalNavInfo.activeChatThreadID) {
const mostRecentThread = mostRecentlyReadThread(
messageStore,
threadInfos,
);
if (mostRecentThread) {
finalNavInfo.activeChatThreadID = mostRecentThread;
}
}
return finalNavInfo;
})();
const { jsURL, fontsURL, cssInclude } = await assetInfoPromise;
// prettier-ignore
res.write(html`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>${getTitle(0)}</title>
<base href="${basePath}" />
<link rel="stylesheet" type="text/css" href="${fontsURL}" />
${cssInclude}
<link
rel="apple-touch-icon"
sizes="180x180"
href="apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="favicon-16x16.png"
/>
<link rel="manifest" href="site.webmanifest" />
- <link rel="mask-icon" href="safari-pinned-tab.svg" color="#b91d47" />
<meta name="apple-mobile-web-app-title" content="Comm" />
<meta name="application-name" content="Comm" />
<meta name="msapplication-TileColor" content="#b91d47" />
<meta name="theme-color" content="#b91d47" />
</head>
<body>
<div id="react-root">
`);
const statePromises = {
navInfo: navInfoPromise,
currentUserInfo: ((currentUserInfoPromise: any): Promise<CurrentUserInfo>),
sessionID: sessionIDPromise,
entryStore: entryStorePromise,
threadStore: threadStorePromise,
userStore: userStorePromise,
messageStore: messageStorePromise,
updatesCurrentAsOf: initialTime,
loadingStatuses: {},
calendarFilters: defaultCalendarFilters,
// We can use paths local to the <base href> on web
urlPrefix: '',
windowDimensions: { width: 0, height: 0 },
baseHref,
connection: {
...defaultConnectionInfo('web', viewer.timeZone),
actualizedCalendarQuery: calendarQuery,
},
watchedThreadIDs: [],
lifecycleState: 'active',
enabledApps: defaultWebEnabledApps,
reportStore: {
enabledReports: defaultEnabledReports,
queuedReports: [],
},
nextLocalID: 0,
timeZone: viewer.timeZone,
userAgent: viewer.userAgent,
cookie: undefined,
deviceToken: undefined,
dataLoaded: viewer.loggedIn,
windowActive: true,
};
const [stateResult, App] = await Promise.all([
promiseAll(statePromises),
appPromise,
]);
const state: AppState = { ...stateResult };
const store: Store<AppState, Action> = createStore(reducer, state);
const routerContext = {};
const clientPath = clientPathFromRouterPath(req.url, appURLFacts);
const reactStream = renderToNodeStream(
<Provider store={store}>
<StaticRouter
location={clientPath}
basename={baseURL}
context={routerContext}
>
<Route path="*" component={App} />
</StaticRouter>
</Provider>,
);
if (routerContext.url) {
throw new ServerError('URL modified during server render!');
}
reactStream.pipe(res, { end: false });
await waitForStream(reactStream);
res.write(html`
</div>
<script>
var preloadedState =
`);
const filteredStatePromises = {
...statePromises,
timeZone: null,
userAgent: null,
};
const jsonStream = streamJSON(res, filteredStatePromises);
await waitForStream(jsonStream);
res.end(html`
;
var baseURL = "${baseURL}";
</script>
<script src="${jsURL}"></script>
</body>
</html>
`);
}
export { websiteResponder };
File Metadata
Details
Attached
Mime Type
image/svg+xml
Expires
Wed, Dec 4, 3:15 PM (1 d, 23 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2612150
Default Alt Text
(13 KB)
Attached To
Mode
rCOMM Comm
Attached
Detach File
Event Timeline
Log In to Comment