scramtag.. TWO!!

This commit is contained in:
Toshit Chawda 2024-12-18 15:28:32 -08:00
parent 35231bf9d9
commit 1343900f7c
No known key found for this signature in database
GPG key ID: 91480ED99E2B3D9D
10 changed files with 141 additions and 49 deletions

View file

@ -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"

View file

@ -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 }

View file

@ -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(),

View file

@ -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"

View file

@ -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());
} }

View file

@ -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,
}) })
} }

View file

@ -117,8 +117,11 @@ 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
// however this code only exists because of recaptcha whatever
// and it would slow down js execution a lot
if let MemberExpression::StaticMemberExpression(s) = it {
if s.property.name == "postMessage" { if s.property.name == "postMessage" {
self.jschanges.add(Rewrite::SetRealmFn { self.jschanges.add(Rewrite::SetRealmFn {
span: s.property.span, span: s.property.span,
@ -128,16 +131,11 @@ where
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 {
{
if let Expression::Identifier(_) = &s.object {
// cull tree - this should be safe // cull tree - this should be safe
return; return;
} }
if let Expression::ThisExpression(_) = &s.object {
return;
}
} }
if self.config.scramitize if self.config.scramitize
@ -146,13 +144,6 @@ where
self.scramitize(s.object.span()); self.scramitize(s.object.span());
} }
} }
_ => {
// TODO
// you could break this with ["postMessage"] etc
// however this code only exists because of recaptcha whatever
// and it would slow down js execution a lot
}
}
walk::walk_member_expression(self, it); walk::walk_member_expression(self, it);
} }

View file

@ -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"]

View file

@ -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)

View file

@ -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);