Page MenuHomePhabricator

No OneTemporary

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

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)

Event Timeline