From 6d03da6d854f2d38a2706ce0cf694cd7848d3173 Mon Sep 17 00:00:00 2001 From: Toshit Chawda Date: Thu, 12 Dec 2024 11:29:55 -0800 Subject: [PATCH] jschange -> rewrite --- rewriter/native/src/main.rs | 2 +- rewriter/rewriter/src/changes.rs | 100 ++++++++++++++++++------------- rewriter/rewriter/src/lib.rs | 10 +++- rewriter/rewriter/src/visitor.rs | 34 +++++------ 4 files changed, 85 insertions(+), 61 deletions(-) diff --git a/rewriter/native/src/main.rs b/rewriter/native/src/main.rs index 2c14b21..bf24e1b 100644 --- a/rewriter/native/src/main.rs +++ b/rewriter/native/src/main.rs @@ -30,7 +30,7 @@ fn dorewrite(data: &str) -> Result { capture_errors: true, do_sourcemaps: true, - scramitize: false, + scramitize: true, strict_rewrites: true, }, ) diff --git a/rewriter/rewriter/src/changes.rs b/rewriter/rewriter/src/changes.rs index 2e9f1ec..4176a6d 100644 --- a/rewriter/rewriter/src/changes.rs +++ b/rewriter/rewriter/src/changes.rs @@ -4,10 +4,10 @@ use oxc::{ }; use smallvec::{smallvec, SmallVec}; -use crate::cfg::Config; +use crate::{cfg::Config, RewriterError}; -#[derive(Debug, PartialEq, Eq)] -pub enum JsChange { +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Rewrite { /// `(cfg.wrapfn(ident))` | `cfg.wrapfn(ident)` WrapFn { span: Span, @@ -72,21 +72,7 @@ pub enum JsChange { }, } -type Changes<'a> = SmallVec<[&'a str; 8]>; - -enum JsChangeInner<'a> { - Wrap { - /// Changes to add before span - before: Changes<'a>, - /// Span to add in between - span: &'a Span, - /// Changes to add after span - after: Changes<'a>, - }, - Replace(Changes<'a>), -} - -impl JsChange { +impl Rewrite { pub fn get_span(&self) -> &Span { match self { Self::WrapFn { span, .. } => span, @@ -120,25 +106,27 @@ impl JsChange { if *wrapped { JsChangeInner::Wrap { before: smallvec!["(", cfg.wrapfn.as_str(), "("], - span, + inner: span, after: smallvec!["))"], } } else { JsChangeInner::Wrap { before: smallvec![cfg.wrapfn.as_str(), "("], - span, + inner: span, after: smallvec![")"], } } } Self::SetRealmFn { span } => JsChangeInner::Wrap { before: smallvec![cfg.setrealmfn.as_str(), "({})."], - span, + inner: span, after: smallvec![], }, - Self::WrapThisFn { .. } => { - JsChangeInner::Replace(smallvec![cfg.wrapthisfn.as_str(), "(this)"]) - } + Self::WrapThisFn { span } => JsChangeInner::Wrap { + before: smallvec![cfg.wrapthisfn.as_str(), "("], + inner: span, + after: smallvec![")"], + }, Self::ImportFn { .. } => JsChangeInner::Replace(smallvec![ "(", cfg.importfn.as_str(), @@ -153,18 +141,19 @@ impl JsChange { "\")" ]), + // maps to insert Self::ScramErr { name, .. } => { JsChangeInner::Replace(smallvec!["$scramerr(", name.as_str(), ");"]) } Self::Scramitize { span } => JsChangeInner::Wrap { before: smallvec!["$scramitize("], - span, + inner: span, after: smallvec![")"], }, Self::Eval { inner, .. } => JsChangeInner::Wrap { before: smallvec!["eval(", cfg.rewritefn.as_str(), "("], - span: inner, + inner, after: smallvec![")"], }, Self::Assignment { @@ -180,9 +169,10 @@ impl JsChange { op.as_str(), "t))(" ], - span: rhsspan, + inner: rhsspan, after: smallvec![")"], }, + // maps to insert Self::ShorthandObj { name, .. } => JsChangeInner::Replace(smallvec![ name.as_str(), ":", @@ -191,6 +181,7 @@ impl JsChange { name.as_str(), ")" ]), + // maps to insert Self::SourceTag { tagname, .. } => JsChangeInner::Replace(smallvec![ "/*scramtag ", tagname.as_str(), @@ -204,25 +195,41 @@ impl JsChange { } } -impl PartialOrd for JsChange { +impl PartialOrd for Rewrite { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for JsChange { +impl Ord for Rewrite { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.get_span().start.cmp(&other.get_span().start) } } +type Changes<'a> = SmallVec<[&'a str; 8]>; + +enum JsChangeInner<'a> { + Wrap { + /// Changes to add before span + before: Changes<'a>, + /// Span to add in between + inner: &'a Span, + /// Changes to add after span + after: Changes<'a>, + }, + Replace { + str: Changes<'a>, + }, +} + pub(crate) struct JsChangeResult { pub js: Vec, pub sourcemap: Vec, } pub(crate) struct JsChanges { - pub inner: Vec, + pub inner: Vec, } impl JsChanges { @@ -230,11 +237,11 @@ impl JsChanges { Self { inner: Vec::new() } } - pub fn add(&mut self, change: JsChange) { + pub fn add(&mut self, change: Rewrite) { self.inner.push(change); } - pub fn perform(&mut self, js: &str, cfg: &Config) -> JsChangeResult + pub fn perform(&mut self, js: &str, cfg: &Config) -> Result where E: Fn(String) -> String, E: Clone, @@ -252,13 +259,17 @@ impl JsChanges { let start = span.start as usize; let end = span.end as usize; - buffer.extend_from_slice(js[offset..start].as_bytes()); + buffer.extend_from_slice( + js.get(offset..start) + .ok_or_else(|| RewriterError::Oob(offset..start))? + .as_bytes(), + ); - let change = change.to_inner(cfg); - match change { + let inner = change.to_inner(cfg); + match inner { JsChangeInner::Wrap { before, - span: wrapspan, + inner: wrapspan, after, } => { // wrap op @@ -268,7 +279,11 @@ impl JsChanges { let wrapstart = wrapspan.start as usize; let wrapend = wrapspan.end as usize; - buffer.extend_from_slice(js[wrapstart..wrapend].as_bytes()); + buffer.extend_from_slice( + js.get(wrapstart..wrapend) + .ok_or_else(|| RewriterError::Oob(wrapstart..wrapend))? + .as_bytes(), + ); for str in after { buffer.extend_from_slice(str.as_bytes()); @@ -284,11 +299,16 @@ impl JsChanges { offset = end; } - buffer.extend_from_slice(js[offset..].as_bytes()); + let js_len = js.len(); + buffer.extend_from_slice( + js.get(offset..js_len) + .ok_or_else(|| RewriterError::Oob(offset..js_len))? + .as_bytes(), + ); - JsChangeResult { + Ok(JsChangeResult { js: buffer, sourcemap: map, - } + }) } } diff --git a/rewriter/rewriter/src/lib.rs b/rewriter/rewriter/src/lib.rs index 8b93d62..e65a807 100644 --- a/rewriter/rewriter/src/lib.rs +++ b/rewriter/rewriter/src/lib.rs @@ -1,5 +1,7 @@ +use std::ops::Range; + use cfg::Config; -use changes::{JsChange, JsChangeResult, JsChanges}; +use changes::{Rewrite, JsChangeResult, JsChanges}; use oxc::{ allocator::Allocator, ast::Visit, @@ -18,6 +20,8 @@ mod visitor; pub enum RewriterError { #[error("oxc panicked in parser")] OxcPanicked, + #[error("out of bounds while applying range: {0:?})")] + Oob(Range), } #[derive(Debug)] @@ -25,7 +29,7 @@ pub struct RewriteResult { pub js: Vec, pub sourcemap: Vec, pub errors: Vec, - pub changes: Vec, + pub changes: Vec, } pub fn rewrite(js: &str, config: Config) -> Result @@ -57,7 +61,7 @@ where config, } = visitor; - let JsChangeResult { js, sourcemap } = jschanges.perform(js, &config); + let JsChangeResult { js, sourcemap } = jschanges.perform(js, &config)?; let JsChanges { inner: changes } = jschanges; Ok(RewriteResult { diff --git a/rewriter/rewriter/src/visitor.rs b/rewriter/rewriter/src/visitor.rs index 4de418d..fbf851c 100644 --- a/rewriter/rewriter/src/visitor.rs +++ b/rewriter/rewriter/src/visitor.rs @@ -15,7 +15,7 @@ use oxc::{ use crate::{ cfg::Config, - changes::{JsChange, JsChanges}, + changes::{Rewrite, JsChanges}, }; // js MUST not be able to get a reference to any of these because sbx @@ -58,7 +58,7 @@ where fn rewrite_ident(&mut self, name: &Atom, span: Span) { if UNSAFE_GLOBALS.contains(&name.as_str()) { - self.jschanges.add(JsChange::WrapFn { + self.jschanges.add(Rewrite::WrapFn { span, wrapped: true, }); @@ -83,7 +83,7 @@ where } fn scramitize(&mut self, span: Span) { - self.jschanges.add(JsChange::Scramitize { span }); + self.jschanges.add(Rewrite::Scramitize { span }); } } @@ -104,7 +104,7 @@ where // } else { // if UNSAFE_GLOBALS.contains(&it.name.as_str()) { - self.jschanges.add(JsChange::WrapFn { + self.jschanges.add(Rewrite::WrapFn { span: it.span, wrapped: false, }); @@ -122,7 +122,7 @@ where match it { MemberExpression::StaticMemberExpression(s) => { if s.property.name == "postMessage" { - self.jschanges.add(JsChange::SetRealmFn { + self.jschanges.add(Rewrite::SetRealmFn { span: s.property.span, }); @@ -159,12 +159,12 @@ where walk::walk_member_expression(self, it); } fn visit_this_expression(&mut self, it: &ThisExpression) { - self.jschanges.add(JsChange::WrapThisFn { span: it.span }); + self.jschanges.add(Rewrite::WrapThisFn { span: it.span }); } fn visit_debugger_statement(&mut self, it: &DebuggerStatement) { // delete debugger statements entirely. some sites will spam debugger as an anti-debugging measure, and we don't want that! - self.jschanges.add(JsChange::Delete { span: it.span }); + self.jschanges.add(Rewrite::Delete { span: it.span }); } // we can't overwrite window.eval in the normal way because that would make everything an @@ -173,7 +173,7 @@ where if let Expression::Identifier(s) = &it.callee { // if it's optional that actually makes it an indirect eval which is handled separately if s.name == "eval" && !it.optional { - self.jschanges.add(JsChange::Eval { + self.jschanges.add(Rewrite::Eval { span: Span::new(it.span.start, it.span.end), inner: Span::new(s.span.end + 1, it.span.end), }); @@ -193,14 +193,14 @@ where fn visit_import_declaration(&mut self, it: &ImportDeclaration<'a>) { let name = it.source.value.to_string(); let text = self.rewrite_url(name); - self.jschanges.add(JsChange::Replace { + self.jschanges.add(Rewrite::Replace { span: it.source.span, text, }); walk::walk_import_declaration(self, it); } fn visit_import_expression(&mut self, it: &ImportExpression<'a>) { - self.jschanges.add(JsChange::ImportFn { + self.jschanges.add(Rewrite::ImportFn { span: Span::new(it.span.start, it.span.start + 6), }); walk::walk_import_expression(self, it); @@ -209,7 +209,7 @@ where fn visit_export_all_declaration(&mut self, it: &ExportAllDeclaration<'a>) { let name = it.source.value.to_string(); let text = self.rewrite_url(name); - self.jschanges.add(JsChange::Replace { + self.jschanges.add(Rewrite::Replace { span: it.source.span, text, }); @@ -218,7 +218,7 @@ where if let Some(source) = &it.source { let name = source.value.to_string(); let text = self.rewrite_url(name); - self.jschanges.add(JsChange::Replace { + self.jschanges.add(Rewrite::Replace { span: source.span, text, }); @@ -234,7 +234,7 @@ where if let Some(h) = &it.handler { if let Some(name) = &h.param { if let Some(name) = name.pattern.get_identifier() { - self.jschanges.add(JsChange::ScramErr { + self.jschanges.add(Rewrite::ScramErr { span: Span::new(h.body.span.start + 1, h.body.span.start + 1), name: name.to_compact_str(), }); @@ -251,7 +251,7 @@ where match &p.value { Expression::Identifier(s) => { if UNSAFE_GLOBALS.contains(&s.name.to_string().as_str()) && p.shorthand { - self.jschanges.add(JsChange::ShorthandObj { + self.jschanges.add(Rewrite::ShorthandObj { span: s.span, name: s.name.to_compact_str(), }); @@ -269,7 +269,7 @@ where fn visit_function_body(&mut self, it: &FunctionBody<'a>) { // tag function for use in sourcemaps if self.config.do_sourcemaps { - self.jschanges.add(JsChange::SourceTag { + self.jschanges.add(Rewrite::SourceTag { span: Span::new(it.span.start, it.span.start), tagname: it.span.start.to_string(), }); @@ -313,7 +313,7 @@ where fn visit_meta_property(&mut self, it: &MetaProperty<'a>) { if it.meta.name == "import" { - self.jschanges.add(JsChange::MetaFn { span: it.span }); + self.jschanges.add(Rewrite::MetaFn { span: it.span }); } } @@ -321,7 +321,7 @@ where match &it.left { AssignmentTarget::AssignmentTargetIdentifier(s) => { if ["location"].contains(&s.name.to_string().as_str()) { - self.jschanges.add(JsChange::Assignment { + self.jschanges.add(Rewrite::Assignment { name: s.name.to_compact_str(), entirespan: it.span, rhsspan: it.right.span(),