Files
CustomBranding/tests/BrandingConfig.test.js
T

130 lines
6.8 KiB
JavaScript

'use strict';
var configModule = require('../temp/tests/BrandingConfig');
var normalize = configModule.normalizeBrandingConfig;
var siteUrl = 'http://sharepoint/sites/portal';
var passed = 0;
function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
passed++;
}
function element(raw) {
return normalize({ placeholdertop: { elements: [raw] } }, siteUrl).config.placeholdertop.elements[0];
}
var empty = normalize({}, siteUrl);
assert(empty.config.schemaVersion === 2, 'Das aktuelle Schema muss Version 2 verwenden.');
assert(empty.config.portalSettings.providerKey === 'custombranding', 'PortalSettings Provider-Key fehlt.');
assert(empty.config.portalSettings.contractVersion === 1, 'PortalSettings Contract-Version fehlt.');
assert(empty.config.enabled === true, 'Branding muss standardmaessig aktiviert sein.');
assert(empty.config.placeholderbottom.elements.length === 1, 'Der Standard-Footer fehlt.');
var defaultFooterLink = empty.config.placeholderbottom.elements[0].children[0];
assert(defaultFooterLink.children[1].content === 'Portal Settings',
'Der Standard-Footer enthaelt nicht den Portal-Settings-Link.');
assert(defaultFooterLink.attributes.href ===
siteUrl + '/SitePages/PortalSettings.aspx', 'Der Standard-Footer verweist nicht auf PortalSettings.');
assert(defaultFooterLink.children[0].attributes.class === 'ms-Icon ms-Icon--Settings',
'Das Settings-Icon fehlt im Standard-Footer.');
assert(empty.config.placeholderbottom.elements[0].styles['text-align'] === 'right',
'Der Standard-Footer muss rechtsbuendig sein.');
assert(empty.config.placeholderbottom.elements[0].styles['background-color'] === undefined &&
defaultFooterLink.styles === undefined,
'Der Standard-Footer darf Hintergrund und Standardtypografie nicht ueberschreiben.');
var emptyBottom = normalize({ placeholderbottom: { elements: [] } }, siteUrl);
assert(emptyBottom.config.placeholderbottom.elements.length === 1,
'Ein geleertes Footer-Array muss auf den Standard-Footer zurueckfallen.');
var customBottom = normalize({
placeholderbottom: { elements: [{ type: 'span', content: 'Eigener Footer' }] }
}, siteUrl);
assert(customBottom.config.placeholderbottom.elements.length === 1 &&
customBottom.config.placeholderbottom.elements[0].content === 'Eigener Footer',
'Ein eigener Footer muss den Standard-Footer ersetzen.');
var legacy = normalize({ elements: [{ type: 'span', content: 'Alt' }] }, siteUrl);
assert(legacy.config.placeholdertop.elements.length === 1, 'Das Legacy-Root-Array muss weiter funktionieren.');
['div', 'span', 'p', 'a', 'button', 'form', 'input', 'img', 'h1', 'h2', 'h3', 'strong', 'em', 'nav', 'section']
.forEach(function (tag) {
var attributes = tag === 'img' ? { alt: '' } : (tag === 'form' ? { action: '/search' } : undefined);
var content = tag === 'a' || tag === 'button' ? tag : undefined;
assert(!!element({ type: tag, content: content, attributes: attributes }), 'Erlaubter Tag fehlt: ' + tag);
});
assert(!element({ type: 'script', content: 'alert(1)' }), 'script darf nicht gerendert werden.');
assert(!element({ type: 'iframe' }), 'iframe darf nicht gerendert werden.');
var safeLink = element({
type: 'a',
content: 'Portal',
attributes: { href: '~sitecollection/SitePages/Home.aspx', target: '_blank', onclick: 'alert(1)' }
});
assert(safeLink.attributes.href === siteUrl + '/SitePages/Home.aspx', '~sitecollection wurde nicht aufgeloest.');
assert(safeLink.attributes.rel === 'noopener noreferrer', 'Externe Fenster brauchen noopener/noreferrer.');
assert(safeLink.attributes.onclick === undefined, 'Event-Attribute duerfen nicht uebernommen werden.');
var unsafeLink = element({ type: 'a', content: 'Unsicher', attributes: { href: 'javascript:alert(1)' } });
assert(unsafeLink.attributes === undefined || unsafeLink.attributes.href === undefined, 'javascript: muss blockiert werden.');
var styled = element({
type: 'div',
styles: { color: '#fff', position: 'fixed', background: 'url(javascript:alert(1))' }
});
assert(styled.styles.color === '#fff', 'Erlaubte Styles muessen erhalten bleiben.');
assert(styled.styles.position === undefined, 'Nicht freigegebene Styles muessen entfernt werden.');
assert(styled.styles.background === undefined, 'CSS url() muss blockiert werden.');
assert(!element({ type: 'img', attributes: { src: '/logo.png' } }), 'Bilder ohne alt muessen verworfen werden.');
assert(!!element({ type: 'img', attributes: { src: '/logo.png', alt: '' } }), 'Dekorative Bilder mit leerem alt sind erlaubt.');
assert(!element({ type: 'button' }), 'Leere Buttons muessen verworfen werden.');
var searchForm = element({
type: 'form',
attributes: { action: '~sitecollection/_layouts/15/search.aspx/siteall', method: 'post' },
children: [
{ type: 'input', attributes: { type: 'text', name: 'q', placeholder: 'Suchen', autocomplete: 'off' } },
{ type: 'button', attributes: { type: 'submit', 'aria-label': 'Suchen' } }
]
});
assert(searchForm.attributes.action === siteUrl + '/_layouts/15/search.aspx/siteall' && searchForm.attributes.method === 'get',
'Suchformulare muessen eine sichere GET-Action verwenden.');
assert(searchForm.children[0].attributes.type === 'search' && searchForm.children[0].attributes.name === 'q',
'Suchfelder muessen auf type=search begrenzt sein.');
assert(searchForm.children[1].attributes.type === 'submit', 'Submit-Buttons in Suchformularen muessen erhalten bleiben.');
assert(!element({ type: 'form', attributes: { action: 'javascript:alert(1)' } }),
'Formulare mit unsicherer Action muessen verworfen werden.');
assert(!element({ type: 'form', attributes: { action: '//evil.example.org/search' } }),
'Formulare mit protokollrelativer Action muessen verworfen werden.');
var css = normalize({
allowedCssHosts: ['cdn.example.org'],
cssfiles: [
{ path: '/SiteAssets/site.css' },
{ path: 'https://cdn.example.org/portal.css', media: 'screen' },
{ path: 'https://evil.example.org/evil.css' },
{ path: 'http://cdn.example.org/mixed.css' },
{ path: '/SiteAssets/site.css' }
]
}, siteUrl).config.cssfiles;
assert(css.length === 2, 'CSS-Allowlist oder Deduplizierung ist fehlerhaft.');
assert(css[0].media === 'all' && css[1].media === 'screen', 'CSS-Media wurde nicht normalisiert.');
var deep = { type: 'div' };
var cursor = deep;
for (var depth = 0; depth < 12; depth++) {
cursor.children = [{ type: 'div' }];
cursor = cursor.children[0];
}
var deepResult = normalize({ placeholdertop: { elements: [deep] } }, siteUrl);
assert(deepResult.warnings.some(function (warning) { return warning.indexOf('depth') >= 0; }), 'Das Tiefenlimit greift nicht.');
var huge = { placeholdertop: { elements: [] }, padding: new Array(100002).join('x') };
assert(normalize(huge, siteUrl).config.placeholdertop.elements.length === 0, 'Zu grosse Konfiguration muss ignoriert werden.');
console.log('BrandingConfig: ' + passed + ' Pruefungen erfolgreich.');