display instance info on the home page

* implements /api/instance
* updates recommended NGINX config
* adds a test on /checkup/
This commit is contained in:
ansuz 2022-05-03 18:20:18 +05:30
parent bbd914b88d
commit 8adeeb21ec
9 changed files with 114 additions and 9 deletions

View file

@ -5,7 +5,8 @@ define([
'/customize/messages.js',
'jquery',
'/api/config',
], function (h, Language, AppConfig, Msg, $, ApiConfig) {
'optional!/api/instance',
], function (h, Language, AppConfig, Msg, $, ApiConfig, Instance) {
var Pages = {};
Pages.setHTML = function (e, html) {
@ -138,6 +139,21 @@ define([
});
var value = AppConfig.hostDescription;
Pages.hostDescription = (value && (value[l] || value.default)) || Msg.home_host;
Pages.Instance = {};
Object.keys(Instance).forEach(function (k) {
var value = Instance[k];
var result = Pages.Instance[k] = value[l] || value.default || undefined;
});
var name;
try {
name = Pages.Instance.name || new URL('/', ApiConfig.httpUnsafeOrigin).host;
} catch (err) {
name = 'CryptPad';
}
Pages.Instance.name = name;
Pages.Instance.description = Pages.Instance.description || Msg.main_catch_phrase;
}());
// used for the about menu

View file

@ -11,7 +11,8 @@ define([
'/customize/messages.js',
'/customize/application_config.js',
'/common/outer/local-store.js',
'/customize/pages.js'
'/customize/pages.js',
//'json!/api/instance',
], function ($, Config, h, Feedback, UI, Hash, Constants, Util, TextFit, Msg, AppConfig, LocalStore, Pages) {
var urlArgs = Config.requireConf.urlArgs;
@ -177,6 +178,19 @@ define([
]));
}
// instance location
var locationBlock;
if (Pages.Instance.location) {
locationBlock = h('div.cp-instance-location', [
h('i.fa.fa-map-pin', {'aria-hidden': 'true'}),
'Encrypted data is hosted in: ', // XXX translate
Pages.Instance.location,
]);
} else {
locationBlock = h('div', h('br')); // XXX
}
return [
h('div#cp-main', [
Pages.infopageTopbar(),
@ -188,12 +202,9 @@ define([
'aria-hidden': 'true',
alt: ''
}),
h('h1', 'CryptPad.fr'), // XXX use instance name
UI.setHTML(h('span.tag-line'), Msg.main_catch_phrase), // XXX Use instance description
h('div.cp-instance-location', [
h('i.fa.fa-map-pin', {'aria-hidden': 'true'}),
'Encrypted data is hosted in: France (OVH)' // XXX Use instance location
]),
h('h1', Pages.Instance.name),
UI.setHTML(h('span.tag-line'), Pages.Instance.description),
locationBlock,
termsLink,
privacyLink,
imprintLink

View file

@ -183,7 +183,7 @@ server {
# /api/config is loaded once per page load and is used to retrieve
# the caching variable which is applied to every other resource
# which is loaded during that session.
location ~ ^/api/(config|broadcast).*$ {
location ~ ^/api/.*$ {
proxy_pass http://localhost:3000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;

View file

@ -261,6 +261,27 @@ var serveBroadcast = makeRouteCache(function (host) {
app.get('/api/config', serveConfig);
app.get('/api/broadcast', serveBroadcast);
var define = function (obj) {
return `define(function (){
return ${JSON.stringify(obj, null, '\t')};
});`
};
app.get('/api/instance', function (req, res) { // XXX use caching?
res.setHeader('Content-Type', 'text/javascript');
res.send(define({
name: {
default: Env.instanceName,
},
description: {
default: Env.instanceDescription,
},
location: {
default: Env.instanceJurisdiction,
},
}));
});
var four04_path = Path.resolve(__dirname + '/customize.dist/404.html');
var fivehundred_path = Path.resolve(__dirname + '/customize.dist/500.html');
var custom_four04_path = Path.resolve(__dirname + '/customize/404.html');

View file

@ -12,6 +12,7 @@
var first = true;
window.addEventListener('error', function (ev) {
if (window.CHECKUP_MAIN_LOADED) { return; }
if (!ev) { return; }
var srcElement = ev.srcElement;
if (!srcElement) { return; }

View file

@ -22,6 +22,8 @@ define([
], function ($, ApiConfig, Assertions, h, Messages, DomReady,
nThen, SFCommonO, Login, Hash, Util, Pinpad,
NetConfig, Pages, Tools, AppConfig) {
window.CHECKUP_MAIN_LOADED = true;
var Assert = Assertions();
var trimSlashes = function (s) {
if (typeof(s) !== 'string') { return s; }
@ -1364,6 +1366,25 @@ define([
});
});
assert(function (cb, msg) {
var url = '/api/instance';
msg.appendChild(h('span', [
link(url, url),
" did not load as expected. This is most likely caused by a missing directive in your reverse proxy or an outdated version of the API server.",
]));
require([
`optional!${url}`,
], function (Instance) {
// if the URL fails to load then an empty object will be returned
// this can be interpreted as a failure, even though the rest of the platform should still work
if (!Object.keys(Instance).length) {
return void cb(Instance);
}
cb(true);
});
});
var serverToken;
Tools.common_xhr('/', function (xhr) {
serverToken = xhr.getResponseHeader('server');

View file

@ -8,6 +8,7 @@ define([
// json plugin
text: '/bower_components/requirejs-plugins/lib/text',
json: '/bower_components/requirejs-plugins/src/json',
optional: '/lib/optional/optional',
// jquery declares itself as literally "jquery" so it cannot be pulled by path :(
"jquery": "/bower_components/jquery/dist/jquery.min",
"mermaid": "/lib/mermaid/mermaid.min",

View file

@ -10,4 +10,5 @@ This file is intended to be used as a log of what third-party source we have ven
* [pdfjs](https://mozilla.github.io/pdf.js/) with some minor modifications to prevent CSP errors
* [mermaid 9.0.0](https://github.com/mermaid-js/mermaid/releases/tag/8.13.4) extends our markdown integration to support a variety of diagram types
* [Fabricjs 4.6.0](https://github.com/fabricjs/fabric.js) and [Fabric-history](https://github.com/lyzerk/fabric-history) for the whiteboard app
* [Requirejs optional module plugin](https://stackoverflow.com/a/27422370)

View file

@ -0,0 +1,33 @@
define("optional", [], {
load : function (moduleName, parentRequire, onload, config){
var onLoadSuccess = function(moduleInstance){
// Module successfully loaded, call the onload callback so that
// requirejs can work its internal magic.
onload(moduleInstance);
}
var onLoadFailure = function(err){
// optional module failed to load.
var failedId = err.requireModules && err.requireModules[0];
console.warn("Could not load optional module: " + failedId);
// Undefine the module to cleanup internal stuff in requireJS
requirejs.undef(failedId);
// Now define the module instance as a simple empty object
// (NOTE: you can return any other value you want here)
define(failedId, [], function(){return {};});
// Now require the module make sure that requireJS thinks
// that is it loaded. Since we've just defined it, requirejs
// will not attempt to download any more script files and
// will just call the onLoadSuccess handler immediately
parentRequire([failedId], onLoadSuccess);
}
parentRequire([moduleName], onLoadSuccess, onLoadFailure, {
accept: 'application/json',
});
}
});