mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #3774 from overleaf/jpa-meta
[frontend] import meta tag processing from das7pads fork GitOrigin-RevId: ca74ff9fbbcb51091a626a45468ff3d24d6136ca
This commit is contained in:
parent
2e305f36bc
commit
535c97e8cf
8 changed files with 135 additions and 47 deletions
|
@ -220,6 +220,10 @@ lint_misc:
|
|||
--ignore-pattern 'modules/*/test/**/*.js' \
|
||||
--max-warnings=0
|
||||
|
||||
lint: lint_pug
|
||||
lint_pug:
|
||||
bin/lint_pug_templates
|
||||
|
||||
lint_in_docker:
|
||||
$(RUN_LINT_FORMAT) make lint -j --output-sync
|
||||
|
||||
|
|
|
@ -69,45 +69,42 @@ html(
|
|||
script(type='text/javascript').
|
||||
window.ga = function() { console.log("would send to GA", arguments) };
|
||||
|
||||
script(type="text/javascript").
|
||||
window.csrfToken = "#{csrfToken}";
|
||||
block meta
|
||||
meta(name="ol-csrfToken" content=csrfToken)
|
||||
//- Configure dynamically loaded assets (via webpack) to be downloaded from CDN
|
||||
//- See: https://webpack.js.org/guides/public-path/#on-the-fly
|
||||
window.baseAssetPath = "#{buildBaseAssetPath()}"
|
||||
meta(name="ol-baseAssetPath" content=buildBaseAssetPath())
|
||||
|
||||
meta(name="ol-usersEmail" content=getUserEmail())
|
||||
meta(name="ol-sharelatex" data-type="json" content={
|
||||
siteUrl: settings.siteUrl,
|
||||
wsUrl,
|
||||
})
|
||||
meta(name="ol-ab" data-type="json" content={})
|
||||
meta(name="ol-user_id" content=getLoggedInUserId())
|
||||
//- Internationalisation settings
|
||||
meta(name="ol-i18n" data-type="json" content={
|
||||
currentLangCode: currentLngCode
|
||||
})
|
||||
//- Expose some settings globally to the frontend
|
||||
meta(name="ol-ExposedSettings" data-type="json" content=ExposedSettings)
|
||||
|
||||
if (typeof(settings.algolia) != "undefined")
|
||||
meta(name="ol-sharelatex.algolia" data-type="json" content={
|
||||
app_id: settings.algolia.app_id,
|
||||
api_key: settings.algolia.read_only_api_key,
|
||||
indexes: settings.algolia.indexes
|
||||
})
|
||||
|
||||
if (typeof(settings.templates) != "undefined")
|
||||
meta(name="ol-sharelatex.templates" data-type="json" content={
|
||||
user_id : settings.templates.user_id,
|
||||
cdnDomain : settings.templates.cdnDomain,
|
||||
indexName : settings.templates.indexName
|
||||
})
|
||||
|
||||
block head-scripts
|
||||
|
||||
meta(id="ol-usersEmail" content=getUserEmail())
|
||||
script.
|
||||
window.sharelatex = {
|
||||
siteUrl: '#{settings.siteUrl}',
|
||||
wsUrl: '#{wsUrl}',
|
||||
};
|
||||
window.ab = {};
|
||||
window.user_id = '#{getLoggedInUserId()}';
|
||||
//- Internationalisation settings
|
||||
window.i18n = {
|
||||
currentLangCode: '#{currentLngCode}'
|
||||
}
|
||||
//- Expose some settings globally to the frontend
|
||||
window.ExposedSettings = JSON.parse('!{StringHelper.stringifyJsonForScript(ExposedSettings)}');
|
||||
|
||||
- if (typeof(settings.algolia) != "undefined")
|
||||
script.
|
||||
window.sharelatex.algolia = {
|
||||
app_id:'#{settings.algolia.app_id}',
|
||||
api_key:'#{settings.algolia.read_only_api_key}',
|
||||
indexes:!{StringHelper.stringifyJsonForScript(settings.algolia.indexes)}
|
||||
}
|
||||
|
||||
- if (typeof(settings.templates) != "undefined")
|
||||
script.
|
||||
window.sharelatex.templates = {
|
||||
user_id : '!{settings.templates.user_id}',
|
||||
cdnDomain : '!{settings.templates.cdnDomain}',
|
||||
indexName : '!{settings.templates.indexName}'
|
||||
}
|
||||
|
||||
|
||||
body
|
||||
if(settings.recaptcha && settings.recaptcha.siteKeyV3)
|
||||
|
|
|
@ -3,18 +3,23 @@ extends ../layout
|
|||
block vars
|
||||
- var suppressNavContentLinks = true
|
||||
|
||||
block content
|
||||
script#data(type="application/json").
|
||||
!{StringHelper.stringifyJsonForScript({ projects, tags, notifications, notificationsInstitution, userAffiliations, userEmails, allInReconfirmNotificationPeriods, reconfirmedViaSAML })}
|
||||
|
||||
script(type="text/javascript").
|
||||
window.data = JSON.parse(document.querySelector("#data").text);
|
||||
window.algolia = {
|
||||
block append meta
|
||||
meta(name="ol-projects" data-type="json" content=projects)
|
||||
meta(name="ol-tags" data-type="json" content=tags)
|
||||
meta(name="ol-notifications" data-type="json" content=notifications)
|
||||
meta(name="ol-notificationsInstitution" data-type="json" content=notificationsInstitution)
|
||||
meta(name="ol-userAffiliations" data-type="json" content=userAffiliations)
|
||||
meta(name="ol-userEmails" data-type="json" content=userEmails)
|
||||
meta(name="ol-allInReconfirmNotificationPeriods" data-type="json" content=allInReconfirmNotificationPeriods)
|
||||
meta(name="ol-reconfirmedViaSAML" content=reconfirmedViaSAML)
|
||||
meta(name="ol-algolia" data-type="json" content={
|
||||
institutions: {
|
||||
app_id: '#{algolia_app_id}',
|
||||
api_key: '#{algolia_api_key}'
|
||||
app_id: algolia_app_id,
|
||||
api_key: algolia_api_key
|
||||
}
|
||||
};
|
||||
})
|
||||
|
||||
block content
|
||||
|
||||
main.content.content-alt.project-list-page(
|
||||
ng-controller="ProjectPageController"
|
||||
|
|
31
services/web/bin/lint_pug_templates
Executable file
31
services/web/bin/lint_pug_templates
Executable file
|
@ -0,0 +1,31 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
TEMPLATES_EXTENDING_META_BLOCK=$(\
|
||||
grep \
|
||||
--files-with-matches \
|
||||
--recursive app/views modules/*/app/views \
|
||||
--regex 'block append meta' \
|
||||
--regex 'block prepend meta' \
|
||||
--regex 'append meta' \
|
||||
--regex 'prepend meta' \
|
||||
)
|
||||
|
||||
for file in ${TEMPLATES_EXTENDING_META_BLOCK}; do
|
||||
if ! grep "$file" --quiet --extended-regexp -e 'extends .+layout'; then
|
||||
cat <<MSG >&2
|
||||
|
||||
ERROR: $file is a partial template and extends 'block meta'.
|
||||
|
||||
Using block append/prepend in a partial will duplicate the block contents into
|
||||
the <body> due to a bug in pug.
|
||||
Putting meta tags in the <body> can lead to Angular XSS.
|
||||
|
||||
You will need to refactor the partial and move the block into the top level
|
||||
page template that extends the global layout.pug.
|
||||
|
||||
MSG
|
||||
exit 1
|
||||
fi
|
||||
done
|
|
@ -22,6 +22,7 @@ import './modules/recursionHelper'
|
|||
import './modules/errorCatcher'
|
||||
import './modules/localStorage'
|
||||
import './modules/sessionStorage'
|
||||
import getMeta from './utils/meta'
|
||||
|
||||
const App = angular
|
||||
.module('SharelatexApp', [
|
||||
|
@ -80,8 +81,7 @@ const App = angular
|
|||
})
|
||||
|
||||
App.run(($rootScope, $templateCache) => {
|
||||
const usersEmailElement = document.getElementById('ol-usersEmail')
|
||||
$rootScope.usersEmail = usersEmailElement && usersEmailElement.content
|
||||
$rootScope.usersEmail = getMeta('ol-usersEmail')
|
||||
|
||||
// UI Select templates are hard-coded and use Glyphicon icons (which we don't import).
|
||||
// The line below simply overrides the hard-coded template with our own, which is
|
||||
|
|
|
@ -14,6 +14,9 @@ import 'libs/select/select'
|
|||
// Polyfill fetch for IE11
|
||||
import 'isomorphic-unfetch'
|
||||
|
||||
// Rewrite meta elements
|
||||
import './utils/meta'
|
||||
|
||||
// Configure dynamically loaded assets (via webpack) to be downloaded from CDN
|
||||
// See: https://webpack.js.org/guides/public-path/#on-the-fly
|
||||
// eslint-disable-next-line no-undef, camelcase
|
||||
|
|
48
services/web/frontend/js/utils/meta.js
Normal file
48
services/web/frontend/js/utils/meta.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
import _ from 'lodash'
|
||||
|
||||
// cache for parsed values
|
||||
const cache = new Map()
|
||||
|
||||
export default function getMeta(name, fallback) {
|
||||
if (cache.has(name)) return cache.get(name)
|
||||
const element = document.head.querySelector(`meta[name="${name}"]`)
|
||||
if (!element) {
|
||||
return fallback
|
||||
}
|
||||
const plainTextValue = element.content
|
||||
let value
|
||||
switch (element.dataset.type) {
|
||||
case 'boolean':
|
||||
// in pug: content=false -> no content field
|
||||
// in pug: content=true -> empty content field
|
||||
value = element.hasAttribute('content')
|
||||
break
|
||||
case 'json':
|
||||
if (!plainTextValue) {
|
||||
// JSON.parse('') throws
|
||||
value = undefined
|
||||
} else {
|
||||
value = JSON.parse(plainTextValue)
|
||||
}
|
||||
break
|
||||
default:
|
||||
value = plainTextValue
|
||||
}
|
||||
cache.set(name, value)
|
||||
return value
|
||||
}
|
||||
|
||||
function convertMetaToWindowAttributes() {
|
||||
window.data = window.data || {}
|
||||
Array.from(document.querySelectorAll('meta[name^="ol-"]'))
|
||||
.map(element => element.name)
|
||||
// process short labels before long ones:
|
||||
// e.g. assign 'sharelatex' before 'sharelatex.templates'
|
||||
.sort()
|
||||
.forEach(nameWithNamespace => {
|
||||
const label = nameWithNamespace.slice('ol-'.length)
|
||||
_.set(window, label, getMeta(nameWithNamespace))
|
||||
_.set(window.data, label, getMeta(nameWithNamespace))
|
||||
})
|
||||
}
|
||||
convertMetaToWindowAttributes()
|
|
@ -1,6 +1,6 @@
|
|||
const OError = require('@overleaf/o-error')
|
||||
const { assertHasStatusCode } = require('./requestHelper')
|
||||
const CSRF_REGEX = /window.csrfToken = "(.+?)"/
|
||||
const CSRF_REGEX = /<meta name="ol-csrfToken" content="(.+?)">/
|
||||
|
||||
function _parseCsrf(body) {
|
||||
const match = CSRF_REGEX.exec(body)
|
||||
|
|
Loading…
Reference in a new issue