mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-12 22:10:01 -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]
|
||||
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"
|
||||
edition = "2021"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.94"
|
||||
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")?;
|
||||
rewrite(
|
||||
data,
|
||||
1024,
|
||||
Config {
|
||||
prefix: "/scrammedjet/".to_string(),
|
||||
base: url.to_string(),
|
||||
|
|
|
@ -3,6 +3,9 @@ name = "rewriter"
|
|||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
oxc = { workspace = true }
|
||||
smallvec = "1.13.2"
|
||||
|
|
|
@ -364,9 +364,9 @@ pub(crate) struct JsChanges {
|
|||
}
|
||||
|
||||
impl JsChanges {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
Self {
|
||||
inner: Default::default(),
|
||||
inner: Vec::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,8 +391,8 @@ impl JsChanges {
|
|||
};
|
||||
}
|
||||
|
||||
// TODO: add sourcemaps
|
||||
let map = Vec::with_capacity(js.len() * 2);
|
||||
let mut map = Vec::with_capacity(js.len() * 2);
|
||||
map.extend_from_slice(&(self.inner.len() as u32).to_le_bytes());
|
||||
|
||||
self.inner.sort_unstable();
|
||||
|
||||
|
@ -406,6 +406,13 @@ impl JsChanges {
|
|||
let inner = change.to_inner(cfg);
|
||||
match inner {
|
||||
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;
|
||||
buffer.extend_from_slice(tryget!(start..loc).as_bytes());
|
||||
for str in str {
|
||||
|
@ -414,6 +421,15 @@ impl JsChanges {
|
|||
buffer.extend_from_slice(tryget!(loc..end).as_bytes());
|
||||
}
|
||||
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 {
|
||||
buffer.extend_from_slice(str.as_bytes());
|
||||
}
|
||||
|
|
|
@ -26,10 +26,15 @@ pub enum RewriterError {
|
|||
pub struct RewriteResult {
|
||||
pub js: Vec<u8>,
|
||||
pub sourcemap: Vec<u8>,
|
||||
pub sourcetag: String,
|
||||
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
|
||||
E: Fn(String) -> String,
|
||||
E: Clone,
|
||||
|
@ -49,14 +54,14 @@ where
|
|||
if ret.panicked {
|
||||
let mut errors = String::new();
|
||||
for error in ret.errors {
|
||||
errors.push_str(&format!("{}", error));
|
||||
errors.push_str(&format!("{error}"));
|
||||
errors.push('\n');
|
||||
}
|
||||
return Err(RewriterError::OxcPanicked(errors));
|
||||
}
|
||||
|
||||
let mut visitor = Visitor {
|
||||
jschanges: JsChanges::new(),
|
||||
jschanges: JsChanges::new(capacity),
|
||||
config,
|
||||
};
|
||||
visitor.visit_program(&ret.program);
|
||||
|
@ -70,6 +75,7 @@ where
|
|||
Ok(RewriteResult {
|
||||
js,
|
||||
sourcemap,
|
||||
sourcetag: config.sourcetag,
|
||||
errors: ret.errors,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -117,40 +117,31 @@ where
|
|||
}
|
||||
|
||||
fn visit_member_expression(&mut self, it: &MemberExpression) {
|
||||
match it {
|
||||
MemberExpression::StaticMemberExpression(s) => {
|
||||
if s.property.name == "postMessage" {
|
||||
self.jschanges.add(Rewrite::SetRealmFn {
|
||||
span: s.property.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
|
||||
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);
|
||||
return; // unwise to walk the rest of the tree
|
||||
}
|
||||
walk::walk_expression(self, &s.object);
|
||||
return; // unwise to walk the rest of the tree
|
||||
}
|
||||
|
||||
if !self.config.strict_rewrites
|
||||
&& !UNSAFE_GLOBALS.contains(&s.property.name.as_str())
|
||||
{
|
||||
if let Expression::Identifier(_) = &s.object {
|
||||
// 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());
|
||||
if !self.config.strict_rewrites && !UNSAFE_GLOBALS.contains(&s.property.name.as_str()) {
|
||||
if let Expression::Identifier(_) | Expression::ThisExpression(_) = &s.object {
|
||||
// cull tree - this should be safe
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// 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
|
||||
|
||||
if self.config.scramitize
|
||||
&& !matches!(s.object, Expression::MetaProperty(_) | Expression::Super(_))
|
||||
{
|
||||
self.scramitize(s.object.span());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@ name = "wasm"
|
|||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
|
|
|
@ -12,7 +12,13 @@ use web_sys::Url;
|
|||
|
||||
#[wasm_bindgen(typescript_custom_section)]
|
||||
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#"
|
||||
|
@ -67,10 +73,10 @@ fn get_str(obj: &JsValue, k: &str) -> Result<String> {
|
|||
}
|
||||
|
||||
fn set_obj(obj: &Object, k: &str, v: &JsValue) -> Result<()> {
|
||||
if !Reflect::set(&obj.into(), &k.into(), v)? {
|
||||
Err(RewriterError::ReflectSetFail(k.to_string()))
|
||||
} else {
|
||||
if Reflect::set(&obj.into(), &k.into(), v)? {
|
||||
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 {
|
||||
(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();
|
||||
set_obj(&obj, "js", &out.js.into())?;
|
||||
set_obj(&obj, "map", &out.sourcemap.into())?;
|
||||
set_obj(&obj, "scramtag", &out.sourcetag.into())?;
|
||||
#[cfg(feature = "debug")]
|
||||
set_obj(&obj, "errors", &errs.into())?;
|
||||
#[cfg(not(feature = "debug"))]
|
||||
|
@ -148,7 +157,7 @@ pub fn rewrite_js(
|
|||
scramjet: &Object,
|
||||
) -> Result<JsRewriterOutput> {
|
||||
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();
|
||||
|
||||
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 before = Instant::now();
|
||||
let out = rewrite(&js, get_config(scramjet, url)?)?;
|
||||
let out = rewrite(&js, 1024, get_config(scramjet, url)?)?;
|
||||
let after = Instant::now();
|
||||
|
||||
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";
|
||||
|
||||
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) =>
|
||||
flagEnabled("sourcemaps", client.url);
|
||||
|
||||
export default function (client: ScramjetClient, self: Self) {
|
||||
// every script will push a sourcemap
|
||||
Object.defineProperty(self, "$scramjet$pushsourcemap", {
|
||||
value: (maps: Mapping[], tag: string) => {
|
||||
sourcemaps[tag] = maps;
|
||||
Object.defineProperty(self, $scramjet.config.globals.pushsourcemapfn, {
|
||||
value: (buf: Array<number>, tag: string) => {
|
||||
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,
|
||||
writable: false,
|
||||
|
@ -60,6 +112,7 @@ export default function (client: ScramjetClient, self: Self) {
|
|||
|
||||
let j = 0;
|
||||
while (j < maps.length) {
|
||||
/* TODO
|
||||
const [str, start, end] = maps[j];
|
||||
if (start < absindex) {
|
||||
j++;
|
||||
|
@ -74,6 +127,7 @@ export default function (client: ScramjetClient, self: Self) {
|
|||
i = start - absindex + offset + str.length;
|
||||
|
||||
j++;
|
||||
*/
|
||||
}
|
||||
|
||||
newString += stringified.slice(i);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue