Skip to content

Instantly share code, notes, and snippets.

@jcubic
Created December 21, 2023 16:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcubic/53af605c7dc32ccb4e814a44eb22f4a4 to your computer and use it in GitHub Desktop.
Save jcubic/53af605c7dc32ccb4e814a44eb22f4a4 to your computer and use it in GitHub Desktop.
CSS-in-JS that supports strict CSP - PoC
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Security-Policy" content="script-src code.jquery.com 'nonce-2726c7f26c'; style-src 'nonce-2726c7f26c'" />
<title></title>
<meta name="Description" content=""/>
<link rel="shortcut icon" href=""/>
<!--[if IE]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<!--
<link href="css/style.css" rel="stylesheet"/>
-->
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script nonce="2726c7f26c" src="style.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<script nonce="2726c7f26c">
const nonce = '2726c7f26c';
$('<p>This is Styled Text</p>').style({
color: 'blue',
background: 'darkgrey',
padding: 10
}, nonce).appendTo('body');
$('<p>This is Styled Text</p>').style({
color: 'blue',
background: 'darkgrey',
padding: 10
}, nonce).appendTo('body');
</script>
</body>
</html>
(() => {
const __DEBUG__ = true;
// based on https://stackoverflow.com/a/18639999/387194
const crc32 = (() => {
const makeCRCTable = () => {
let c;
const crcTable = [];
for(let n =0; n < 256; n++){
c = n;
for(let k =0; k < 8; k++){
c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
}
crcTable[n] = c;
}
return crcTable;
};
const crcTable = makeCRCTable();
return (str) => {
let crc = 0 ^ (-1);
for (let i = 0; i < str.length; i++ ) {
crc = (crc >>> 8) ^ crcTable[(crc ^ str.charCodeAt(i)) & 0xFF];
}
return (crc ^ (-1)) >>> 0;
};
})();
const hash = (string) => {
return crc32(string).toString(16);
};
function empty_rule(sheet, class_name) {
const index = sheet.cssRules.length;
sheet.insertRule(`.${class_name} { }`, index);
return sheet.cssRules[index];
}
function make_style(nonce = null) {
return $(`<style type="text/css"${nonce ? ` nonce="${nonce}"` : ''}/>`).appendTo(document.head);
}
function set_css(sheet, class_name, style) {
const selector = `.${class_name}`;
let rule = [...sheet.cssRules].find(rule => {
return rule.selectorText === selector;
});
if (!rule) {
rule = empty_rule(sheet, class_name);
}
Object.assign(rule.style, style);
}
function dump_css(sheet) {
return [...sheet.cssRules].map(rule => rule.cssText).join('\n')
}
const cache = new Map();
$.fn.style = function(style, nonce = null) {
const repr = JSON.stringify(style);
const class_name = `terminal-${hash(repr)}`;
if (!cache.has(class_name)) {
const $style = make_style(nonce);
const { sheet } = $style.get(0);
set_css(sheet, class_name, style);
cache.set(class_name, true);
if (__DEBUG__) {
$style.text(dump_css(sheet));
}
}
this.addClass(class_name);
return this;
};
})();
@jcubic
Copy link
Author

jcubic commented Dec 21, 2023

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment