mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-13 06:20:02 -04:00
scramtag.. TWO!!
This commit is contained in:
parent
35231bf9d9
commit
1343900f7c
10 changed files with 141 additions and 49 deletions
|
@ -11,3 +11,9 @@ panic = "abort"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
oxc = "0.41.0"
|
oxc = "0.41.0"
|
||||||
|
|
||||||
|
[workspace.lints.clippy]
|
||||||
|
pedantic = { level = "warn", priority = -1 }
|
||||||
|
struct-excessive-bools = "allow"
|
||||||
|
missing-errors-doc = "allow"
|
||||||
|
cast-possible-truncation = "allow"
|
||||||
|
|
|
@ -3,6 +3,9 @@ name = "native"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.94"
|
anyhow = "1.0.94"
|
||||||
oxc = { workspace = true }
|
oxc = { workspace = true }
|
||||||
|
|
|
@ -10,6 +10,7 @@ fn dorewrite(data: &str) -> Result<RewriteResult> {
|
||||||
let url = Url::from_str("https://google.com/glorngle/si.js").context("failed to make url")?;
|
let url = Url::from_str("https://google.com/glorngle/si.js").context("failed to make url")?;
|
||||||
rewrite(
|
rewrite(
|
||||||
data,
|
data,
|
||||||
|
1024,
|
||||||
Config {
|
Config {
|
||||||
prefix: "/scrammedjet/".to_string(),
|
prefix: "/scrammedjet/".to_string(),
|
||||||
base: url.to_string(),
|
base: url.to_string(),
|
||||||
|
|
|
@ -3,6 +3,9 @@ name = "rewriter"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
oxc = { workspace = true }
|
oxc = { workspace = true }
|
||||||
smallvec = "1.13.2"
|
smallvec = "1.13.2"
|
||||||
|
|
|
@ -364,9 +364,9 @@ pub(crate) struct JsChanges {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JsChanges {
|
impl JsChanges {
|
||||||
pub fn new() -> Self {
|
pub fn new(capacity: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: Default::default(),
|
inner: Vec::with_capacity(capacity),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,8 +391,8 @@ impl JsChanges {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add sourcemaps
|
let mut map = Vec::with_capacity(js.len() * 2);
|
||||||
let map = Vec::with_capacity(js.len() * 2);
|
map.extend_from_slice(&(self.inner.len() as u32).to_le_bytes());
|
||||||
|
|
||||||
self.inner.sort_unstable();
|
self.inner.sort_unstable();
|
||||||
|
|
||||||
|
@ -406,6 +406,13 @@ impl JsChanges {
|
||||||
let inner = change.to_inner(cfg);
|
let inner = change.to_inner(cfg);
|
||||||
match inner {
|
match inner {
|
||||||
JsChangeInner::Insert { loc, str } => {
|
JsChangeInner::Insert { loc, str } => {
|
||||||
|
// INSERT op
|
||||||
|
map.push(0);
|
||||||
|
// start
|
||||||
|
map.extend_from_slice(&loc.to_le_bytes());
|
||||||
|
// size
|
||||||
|
map.extend_from_slice(&(str.len() as u32).to_le_bytes());
|
||||||
|
|
||||||
let loc = loc as usize;
|
let loc = loc as usize;
|
||||||
buffer.extend_from_slice(tryget!(start..loc).as_bytes());
|
buffer.extend_from_slice(tryget!(start..loc).as_bytes());
|
||||||
for str in str {
|
for str in str {
|
||||||
|
@ -414,6 +421,15 @@ impl JsChanges {
|
||||||
buffer.extend_from_slice(tryget!(loc..end).as_bytes());
|
buffer.extend_from_slice(tryget!(loc..end).as_bytes());
|
||||||
}
|
}
|
||||||
JsChangeInner::Replace { str } => {
|
JsChangeInner::Replace { str } => {
|
||||||
|
// REPLACE op
|
||||||
|
map.push(1);
|
||||||
|
// start
|
||||||
|
map.extend_from_slice(&span.start.to_le_bytes());
|
||||||
|
// end
|
||||||
|
map.extend_from_slice(&span.end.to_le_bytes());
|
||||||
|
// oldstr
|
||||||
|
map.extend_from_slice(tryget!(start..end).as_bytes());
|
||||||
|
|
||||||
for str in str {
|
for str in str {
|
||||||
buffer.extend_from_slice(str.as_bytes());
|
buffer.extend_from_slice(str.as_bytes());
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,10 +26,15 @@ pub enum RewriterError {
|
||||||
pub struct RewriteResult {
|
pub struct RewriteResult {
|
||||||
pub js: Vec<u8>,
|
pub js: Vec<u8>,
|
||||||
pub sourcemap: Vec<u8>,
|
pub sourcemap: Vec<u8>,
|
||||||
|
pub sourcetag: String,
|
||||||
pub errors: Vec<OxcDiagnostic>,
|
pub errors: Vec<OxcDiagnostic>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rewrite<E>(js: &str, config: Config<E>) -> Result<RewriteResult, RewriterError>
|
pub fn rewrite<E>(
|
||||||
|
js: &str,
|
||||||
|
capacity: usize,
|
||||||
|
config: Config<E>,
|
||||||
|
) -> Result<RewriteResult, RewriterError>
|
||||||
where
|
where
|
||||||
E: Fn(String) -> String,
|
E: Fn(String) -> String,
|
||||||
E: Clone,
|
E: Clone,
|
||||||
|
@ -49,14 +54,14 @@ where
|
||||||
if ret.panicked {
|
if ret.panicked {
|
||||||
let mut errors = String::new();
|
let mut errors = String::new();
|
||||||
for error in ret.errors {
|
for error in ret.errors {
|
||||||
errors.push_str(&format!("{}", error));
|
errors.push_str(&format!("{error}"));
|
||||||
errors.push('\n');
|
errors.push('\n');
|
||||||
}
|
}
|
||||||
return Err(RewriterError::OxcPanicked(errors));
|
return Err(RewriterError::OxcPanicked(errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut visitor = Visitor {
|
let mut visitor = Visitor {
|
||||||
jschanges: JsChanges::new(),
|
jschanges: JsChanges::new(capacity),
|
||||||
config,
|
config,
|
||||||
};
|
};
|
||||||
visitor.visit_program(&ret.program);
|
visitor.visit_program(&ret.program);
|
||||||
|
@ -70,6 +75,7 @@ where
|
||||||
Ok(RewriteResult {
|
Ok(RewriteResult {
|
||||||
js,
|
js,
|
||||||
sourcemap,
|
sourcemap,
|
||||||
|
sourcetag: config.sourcetag,
|
||||||
errors: ret.errors,
|
errors: ret.errors,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,40 +117,31 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_member_expression(&mut self, it: &MemberExpression) {
|
fn visit_member_expression(&mut self, it: &MemberExpression) {
|
||||||
match it {
|
// TODO
|
||||||
MemberExpression::StaticMemberExpression(s) => {
|
// you could break this with ["postMessage"] etc
|
||||||
if s.property.name == "postMessage" {
|
// however this code only exists because of recaptcha whatever
|
||||||
self.jschanges.add(Rewrite::SetRealmFn {
|
// and it would slow down js execution a lot
|
||||||
span: s.property.span,
|
if let MemberExpression::StaticMemberExpression(s) = it {
|
||||||
});
|
if s.property.name == "postMessage" {
|
||||||
|
self.jschanges.add(Rewrite::SetRealmFn {
|
||||||
|
span: s.property.span,
|
||||||
|
});
|
||||||
|
|
||||||
walk::walk_expression(self, &s.object);
|
walk::walk_expression(self, &s.object);
|
||||||
return; // unwise to walk the rest of the tree
|
return; // unwise to walk the rest of the tree
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.config.strict_rewrites
|
if !self.config.strict_rewrites && !UNSAFE_GLOBALS.contains(&s.property.name.as_str()) {
|
||||||
&& !UNSAFE_GLOBALS.contains(&s.property.name.as_str())
|
if let Expression::Identifier(_) | Expression::ThisExpression(_) = &s.object {
|
||||||
{
|
// cull tree - this should be safe
|
||||||
if let Expression::Identifier(_) = &s.object {
|
return;
|
||||||
// cull tree - this should be safe
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if let Expression::ThisExpression(_) = &s.object {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.config.scramitize
|
|
||||||
&& !matches!(s.object, Expression::MetaProperty(_) | Expression::Super(_))
|
|
||||||
{
|
|
||||||
self.scramitize(s.object.span());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
|
||||||
// TODO
|
if self.config.scramitize
|
||||||
// you could break this with ["postMessage"] etc
|
&& !matches!(s.object, Expression::MetaProperty(_) | Expression::Super(_))
|
||||||
// however this code only exists because of recaptcha whatever
|
{
|
||||||
// and it would slow down js execution a lot
|
self.scramitize(s.object.span());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,9 @@ name = "wasm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,13 @@ use web_sys::Url;
|
||||||
|
|
||||||
#[wasm_bindgen(typescript_custom_section)]
|
#[wasm_bindgen(typescript_custom_section)]
|
||||||
const REWRITER_OUTPUT: &'static str = r#"
|
const REWRITER_OUTPUT: &'static str = r#"
|
||||||
type RewriterOutput = { js: Uint8Array, errors: string[], duration: bigint };
|
type RewriterOutput = {
|
||||||
|
js: Uint8Array,
|
||||||
|
map: Uint8Array,
|
||||||
|
scramtag: string,
|
||||||
|
errors: string[],
|
||||||
|
duration: bigint
|
||||||
|
};
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
#[wasm_bindgen(inline_js = r#"
|
#[wasm_bindgen(inline_js = r#"
|
||||||
|
@ -67,10 +73,10 @@ fn get_str(obj: &JsValue, k: &str) -> Result<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_obj(obj: &Object, k: &str, v: &JsValue) -> Result<()> {
|
fn set_obj(obj: &Object, k: &str, v: &JsValue) -> Result<()> {
|
||||||
if !Reflect::set(&obj.into(), &k.into(), v)? {
|
if Reflect::set(&obj.into(), &k.into(), v)? {
|
||||||
Err(RewriterError::ReflectSetFail(k.to_string()))
|
|
||||||
} else {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(RewriterError::ReflectSetFail(k.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +117,7 @@ fn get_config(scramjet: &Object, url: String) -> Result<Config<impl Fn(String) -
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
|
||||||
fn duration_to_millis_f64(duration: Duration) -> f64 {
|
fn duration_to_millis_f64(duration: Duration) -> f64 {
|
||||||
(duration.as_secs() as f64) * 1_000f64 + (duration.subsec_nanos() as f64) / 1_000_000f64
|
(duration.as_secs() as f64) * 1_000f64 + (duration.subsec_nanos() as f64) / 1_000_000f64
|
||||||
}
|
}
|
||||||
|
@ -131,6 +138,8 @@ fn create_rewriter_output(
|
||||||
|
|
||||||
let obj = Object::new();
|
let obj = Object::new();
|
||||||
set_obj(&obj, "js", &out.js.into())?;
|
set_obj(&obj, "js", &out.js.into())?;
|
||||||
|
set_obj(&obj, "map", &out.sourcemap.into())?;
|
||||||
|
set_obj(&obj, "scramtag", &out.sourcetag.into())?;
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
set_obj(&obj, "errors", &errs.into())?;
|
set_obj(&obj, "errors", &errs.into())?;
|
||||||
#[cfg(not(feature = "debug"))]
|
#[cfg(not(feature = "debug"))]
|
||||||
|
@ -148,7 +157,7 @@ pub fn rewrite_js(
|
||||||
scramjet: &Object,
|
scramjet: &Object,
|
||||||
) -> Result<JsRewriterOutput> {
|
) -> Result<JsRewriterOutput> {
|
||||||
let before = Instant::now();
|
let before = Instant::now();
|
||||||
let out = rewrite(&js, get_config(scramjet, url)?)?;
|
let out = rewrite(&js, 1024, get_config(scramjet, url)?)?;
|
||||||
let after = Instant::now();
|
let after = Instant::now();
|
||||||
|
|
||||||
create_rewriter_output(out, script_url, js, after - before)
|
create_rewriter_output(out, script_url, js, after - before)
|
||||||
|
@ -165,7 +174,7 @@ pub fn rewrite_js_from_arraybuffer(
|
||||||
let js = unsafe { String::from_utf8_unchecked(js) };
|
let js = unsafe { String::from_utf8_unchecked(js) };
|
||||||
|
|
||||||
let before = Instant::now();
|
let before = Instant::now();
|
||||||
let out = rewrite(&js, get_config(scramjet, url)?)?;
|
let out = rewrite(&js, 1024, get_config(scramjet, url)?)?;
|
||||||
let after = Instant::now();
|
let after = Instant::now();
|
||||||
|
|
||||||
create_rewriter_output(out, script_url, js, after - before)
|
create_rewriter_output(out, script_url, js, after - before)
|
||||||
|
|
|
@ -1,18 +1,70 @@
|
||||||
import { flagEnabled } from "../../scramjet";
|
import { $scramjet, flagEnabled } from "../../scramjet";
|
||||||
import { ScramjetClient } from "../client";
|
import { ScramjetClient } from "../client";
|
||||||
|
|
||||||
type Mapping = [string, number, number];
|
enum RewriteType {
|
||||||
|
Insert = 0,
|
||||||
|
Replace = 1,
|
||||||
|
}
|
||||||
|
|
||||||
const sourcemaps: Record<string, Mapping[]> = {};
|
type Rewrite =
|
||||||
|
| {
|
||||||
|
type: RewriteType.Insert;
|
||||||
|
// start of insertion
|
||||||
|
start: number;
|
||||||
|
// size of insertion
|
||||||
|
size: number;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: RewriteType.Replace;
|
||||||
|
// start of replacement
|
||||||
|
start: number;
|
||||||
|
// end of replacement
|
||||||
|
end: number;
|
||||||
|
// old string
|
||||||
|
str: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sourcemaps: Record<string, Rewrite[]> = {};
|
||||||
|
|
||||||
export const enabled = (client: ScramjetClient) =>
|
export const enabled = (client: ScramjetClient) =>
|
||||||
flagEnabled("sourcemaps", client.url);
|
flagEnabled("sourcemaps", client.url);
|
||||||
|
|
||||||
export default function (client: ScramjetClient, self: Self) {
|
export default function (client: ScramjetClient, self: Self) {
|
||||||
// every script will push a sourcemap
|
// every script will push a sourcemap
|
||||||
Object.defineProperty(self, "$scramjet$pushsourcemap", {
|
Object.defineProperty(self, $scramjet.config.globals.pushsourcemapfn, {
|
||||||
value: (maps: Mapping[], tag: string) => {
|
value: (buf: Array<number>, tag: string) => {
|
||||||
sourcemaps[tag] = maps;
|
const sourcemap = Uint8Array.from(buf);
|
||||||
|
const view = new DataView(sourcemap.buffer);
|
||||||
|
const decoder = new TextDecoder("utf-8");
|
||||||
|
|
||||||
|
const rewrites = [];
|
||||||
|
|
||||||
|
const rewritelen = view.getUint32(0, true);
|
||||||
|
let cursor = 0;
|
||||||
|
for (let i = 0; i < rewritelen; i++) {
|
||||||
|
const type = view.getUint8(cursor) as RewriteType;
|
||||||
|
cursor += 1;
|
||||||
|
|
||||||
|
if (type == RewriteType.Insert) {
|
||||||
|
const start = view.getUint32(cursor, true);
|
||||||
|
cursor += 4;
|
||||||
|
const size = view.getUint32(cursor, true);
|
||||||
|
cursor += 4;
|
||||||
|
|
||||||
|
rewrites.push({ type, start, size });
|
||||||
|
} else if (type == RewriteType.Replace) {
|
||||||
|
const start = view.getUint32(cursor, true);
|
||||||
|
cursor += 4;
|
||||||
|
const end = view.getUint32(cursor, true);
|
||||||
|
cursor += 4;
|
||||||
|
|
||||||
|
const str = decoder.decode(sourcemap.subarray(start, end));
|
||||||
|
|
||||||
|
rewrites.push({ type, start, end, str });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcemaps[tag] = rewrites;
|
||||||
},
|
},
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
|
@ -60,6 +112,7 @@ export default function (client: ScramjetClient, self: Self) {
|
||||||
|
|
||||||
let j = 0;
|
let j = 0;
|
||||||
while (j < maps.length) {
|
while (j < maps.length) {
|
||||||
|
/* TODO
|
||||||
const [str, start, end] = maps[j];
|
const [str, start, end] = maps[j];
|
||||||
if (start < absindex) {
|
if (start < absindex) {
|
||||||
j++;
|
j++;
|
||||||
|
@ -74,6 +127,7 @@ export default function (client: ScramjetClient, self: Self) {
|
||||||
i = start - absindex + offset + str.length;
|
i = start - absindex + offset + str.length;
|
||||||
|
|
||||||
j++;
|
j++;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
newString += stringified.slice(i);
|
newString += stringified.slice(i);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue