Skip to content

Commit 169a59d

Browse files
committed
add eruda
1 parent ddd52ab commit 169a59d

File tree

12 files changed

+458
-1
lines changed

12 files changed

+458
-1
lines changed

app/src/main/assets/eruda.mjs

Lines changed: 377 additions & 0 deletions
Large diffs are not rendered by default.

app/src/main/assets/node/buffer.mjs

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
var v=function(){};function u(e,t={}){v.prototype.name=e;let r={};return new Proxy(v,{get(n,a){return a==="caller"?null:a==="__createMock__"?u:a==="__unenv__"?!0:a in t?t[a]:r[a]=r[a]||u(`${e}.${a.toString()}`)},apply(n,a,o){return u(`${e}()`)},construct(n,a,o){return u(`[${e}]`)},enumerate(){return[]}})}var d=u("mock");function m(e){return new Error(`[unenv] ${e} is not implemented yet!`)}function s(e){return Object.assign(()=>{throw m(e)},{__unenv__:!0})}var b=Object.freeze(Object.create(null,{__unenv__:{get:()=>!0}})),p=Object.create(null),h=globalThis.process?.env,l=e=>h||globalThis.__env__||(e?p:globalThis),x=new Proxy(p,{get(e,t){return l()[t]??p[t]},has(e,t){let r=l();return t in r||t in p},set(e,t,r){let n=l(!0);return n[t]=r,!0},deleteProperty(e,t){let r=l(!0);return delete r[t],!0},ownKeys(){let e=l();return Object.keys(e)}}),k=Object.assign(function(e){let t=Date.now(),r=Math.trunc(t/1e3),n=t%1e3*1e6;if(e){let a=r-e[0],o=n-e[0];return o<0&&(a=a-1,o=1e9+o),[a,o]}return[r,n]},{bigint:function(){return BigInt(Date.now()*1e6)}}),E=globalThis.queueMicrotask?(e,...t)=>{globalThis.queueMicrotask(e.bind(void 0,...t))}:M();function M(){let e=[],t=!1,r,n=-1;function a(){!t||!r||(t=!1,r.length>0?e=[...r,...e]:n=-1,e.length>0&&o())}function o(){if(t)return;let g=setTimeout(a);t=!0;let c=e.length;for(;c;){for(r=e,e=[];++n<c;)r&&r[n]();n=-1,c=e.length}r=void 0,t=!1,clearTimeout(g)}return(g,...c)=>{e.push(g.bind(void 0,...c)),e.length===1&&!t&&setTimeout(o)}}var w="unenv",L=[],y="",C={ares:"",http_parser:"",icu:"",modules:"",node:"",openssl:"",uv:"",v8:"",zlib:""};function i(){return _}var P=i,U=i,O=i,A=i,j=i,N=i,T=function(e){return e==="message"||e==="multipleResolves"?_:!1},R=i,I=i,S=function(e){return[]},B=()=>0,D=function(e){throw new Error("[unenv] process.binding is not supported")},f="/",F=function(){return f},$=function(e){f=e},q=function(){return 0},z=function(){return 1e3},H=function(){return 1e3},W=function(){return 1e3},K=function(){return 1e3},G=function(){return[]},J=e=>{},Q=s("process.abort"),V=new Set,X="",Y="",Z=b,ee=!1,se=()=>0,te=()=>0,re=s("process.cpuUsage"),ae=0,ne=s("process.dlopen"),ie=i,oe=i,ce=s("process.eventNames"),ue=[],le="",de=s("process.exit"),pe=Object.create({inspector:void 0,debug:void 0,uv:void 0,ipv6:void 0,tls_alpn:void 0,tls_sni:void 0,tls_ocsp:void 0,tls:void 0,cached_builtins:void 0}),ge=()=>[],_e=s("process.getMaxListeners"),ve=s("process.kill"),fe=Object.assign(()=>({arrayBuffers:0,rss:0,external:0,heapTotal:0,heapUsed:0}),{rss:()=>0}),me=1e3,be="",he=1e3,xe=s("process.rawListeners"),ke=Object.create({name:"",lts:"",sourceUrl:void 0,headersUrl:void 0}),Ee=Object.create({compact:void 0,directory:void 0,filename:void 0,getReport:s("process.report.getReport"),reportOnFatalError:void 0,reportOnSignal:void 0,reportOnUncaughtException:void 0,signal:void 0,writeReport:s("process.report.writeReport")}),Me=s("process.resourceUsage"),we=s("process.setegid"),Le=s("process.seteuid"),ye=s("process.setgid"),Ce=s("process.setgroups"),Pe=s("process.setuid"),Ue=s("process.setMaxListeners"),Oe=s("process.setSourceMapsEnabled"),Ae=d.__createMock__("process.stdout"),je=d.__createMock__("process.stderr"),Ne=d.__createMock__("process.stdin"),Te=!1,Re=()=>0,Ie=0,Se=s("process.setUncaughtExceptionCaptureCallback"),Be=()=>!1,De=!1,Fe=s("process.loadEnvFile"),$e=void 0,qe={has:()=>!1},ze={ref(){},unref(){}},He=!1,We={register(){},unregister(){},registerBeforeExit(){}},Ke=s("process.assert"),Ge=s("process.openStdin"),Je=s("process._debugEnd"),Qe=s("process._debugProcess"),Ve=s("process._fatalException"),Xe=s("process._getActiveHandles"),Ye=s("process._getActiveRequests"),Ze=s("process._kill"),es=[],ss=s("process._rawDebug"),ts=s("process._startProfilerIdleNotifier"),rs=s("process.__stopProfilerIdleNotifier"),as=s("process._tickCallback"),hs=s("process._linkedBinding"),ns=void 0,is=s("process.initgroups"),os=[],cs=i,us=!1,ls=[],ds=0,ps=0,_={_events:ls,_eventsCount:ds,_exiting:us,_maxListeners:ps,_debugEnd:Je,_debugProcess:Qe,_fatalException:Ve,_getActiveHandles:Xe,_getActiveRequests:Ye,_kill:Ze,_preload_modules:es,_rawDebug:ss,_startProfilerIdleNotifier:ts,_stopProfilerIdleNotifier:rs,_tickCallback:as,domain:ns,initgroups:is,moduleLoadList:os,reallyExit:cs,exitCode:Ie,abort:Q,addListener:U,allowedNodeEnvironmentFlags:V,hasUncaughtExceptionCaptureCallback:Be,setUncaughtExceptionCaptureCallback:Se,loadEnvFile:Fe,sourceMapsEnabled:De,throwDeprecation:He,mainModule:$e,permission:qe,channel:ze,arch:X,argv:L,argv0:Y,assert:Ke,binding:D,chdir:$,config:Z,connected:ee,constrainedMemory:se,availableMemory:te,cpuUsage:re,cwd:F,debugPort:ae,dlopen:ne,disconnect:ie,emit:T,emitWarning:oe,env:x,eventNames:ce,execArgv:ue,execPath:le,exit:de,finalization:We,features:pe,getBuiltinModule:J,getegid:z,geteuid:H,getgid:W,getgroups:G,getuid:K,getActiveResourcesInfo:ge,getMaxListeners:_e,hrtime:k,kill:ve,listeners:S,listenerCount:B,memoryUsage:fe,nextTick:E,on:P,off:A,once:O,openStdin:Ge,pid:me,platform:be,ppid:he,prependListener:R,prependOnceListener:I,rawListeners:xe,release:ke,removeAllListeners:N,removeListener:j,report:Ee,resourceUsage:Me,setegid:we,seteuid:Le,setgid:ye,setgroups:Ce,setuid:Pe,setMaxListeners:Ue,setSourceMapsEnabled:Oe,stderr:je,stdin:Ne,stdout:Ae,title:w,traceDeprecation:Te,umask:q,uptime:Re,version:y,versions:C},xs=_;export{Je as _debugEnd,Qe as _debugProcess,ls as _events,ds as _eventsCount,us as _exiting,Ve as _fatalException,Xe as _getActiveHandles,Ye as _getActiveRequests,Ze as _kill,hs as _linkedBinding,ps as _maxListeners,es as _preload_modules,ss as _rawDebug,ts as _startProfilerIdleNotifier,rs as _stopProfilerIdleNotifier,as as _tickCallback,Q as abort,U as addListener,V as allowedNodeEnvironmentFlags,X as arch,L as argv,Y as argv0,Ke as assert,te as availableMemory,D as binding,$ as chdir,Z as config,se as constrainedMemory,re as cpuUsage,F as cwd,ae as debugPort,xs as default,ne as dlopen,ns as domain,T as emit,oe as emitWarning,x as env,ce as eventNames,ue as execArgv,le as execPath,de as exit,Ie as exitCode,pe as features,We as finalization,ge as getActiveResourcesInfo,J as getBuiltinModule,_e as getMaxListeners,z as getegid,H as geteuid,W as getgid,G as getgroups,K as getuid,Be as hasUncaughtExceptionCaptureCallback,k as hrtime,is as initgroups,ve as kill,B as listenerCount,S as listeners,Fe as loadEnvFile,fe as memoryUsage,os as moduleLoadList,E as nextTick,A as off,P as on,O as once,Ge as openStdin,me as pid,be as platform,he as ppid,R as prependListener,I as prependOnceListener,_ as process,xe as rawListeners,cs as reallyExit,ke as release,N as removeAllListeners,j as removeListener,Ee as report,Me as resourceUsage,Ue as setMaxListeners,Oe as setSourceMapsEnabled,Se as setUncaughtExceptionCaptureCallback,we as setegid,Le as seteuid,ye as setgid,Ce as setgroups,Pe as setuid,De as sourceMapsEnabled,je as stderr,Ne as stdin,Ae as stdout,w as title,q as umask,Re as uptime,y as version,C as versions};

app/src/main/kotlin/com/dergoogler/mmrl/datastore/UserPreferencesCompat.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ data class UserPreferencesCompat(
4343
val allowCancelAction: Boolean,
4444
val useShellToLoadWebUIAssets: Boolean,
4545
val blacklistAlerts: Boolean,
46+
val injectEruda: List<String>,
4647
val allowedFsModules: List<String>,
4748
val allowedKsuModules: List<String>,
4849
val repositoryMenu: RepositoryMenuCompat,
@@ -79,6 +80,7 @@ data class UserPreferencesCompat(
7980
allowCancelAction = original.allowCancelAction,
8081
useShellToLoadWebUIAssets = original.useShellToLoadWebUIAssets,
8182
blacklistAlerts = original.blacklistAlerts,
83+
injectEruda = original.injectEruda.split(","),
8284
allowedFsModules = original.allowedFsModules.split(","),
8385
allowedKsuModules = original.allowedKsuModules.split(","),
8486
repositoryMenu = when {
@@ -126,6 +128,7 @@ data class UserPreferencesCompat(
126128
.setUseShellForModuleAction(useShellForModuleAction)
127129
.setWebuiAllowRestrictedPaths(webuiAllowRestrictedPaths)
128130
.setBlacklistAlerts(blacklistAlerts)
131+
.setInjectEruda(injectEruda.joinToString(","))
129132
.setClearInstallTerminal(clearInstallTerminal)
130133
.setAllowCancelInstall(allowCancelInstall)
131134
.setAllowCancelAction(allowCancelAction)
@@ -167,6 +170,7 @@ data class UserPreferencesCompat(
167170
useShellForModuleAction = true,
168171
webuiAllowRestrictedPaths = false,
169172
blacklistAlerts = true,
173+
injectEruda = emptyList(),
170174
allowedFsModules = emptyList(),
171175
allowedKsuModules = emptyList(),
172176
repositoriesMenu = RepositoriesMenuCompat.default(),

app/src/main/kotlin/com/dergoogler/mmrl/datastore/UserPreferencesDataSource.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,14 @@ class UserPreferencesDataSource @Inject constructor(
238238
}
239239
}
240240

241+
suspend fun setInjectEruda(value: List<String>) = withContext(Dispatchers.IO) {
242+
userPreferences.updateData {
243+
it.copy(
244+
injectEruda = value
245+
)
246+
}
247+
}
248+
241249
suspend fun setAllowedFsModules(value: List<String>) = withContext(Dispatchers.IO) {
242250
userPreferences.updateData {
243251
it.copy(

app/src/main/kotlin/com/dergoogler/mmrl/repository/UserPreferencesRepository.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ class UserPreferencesRepository @Inject constructor(
9292
suspend fun setBlacklistAlerts(value: Boolean) =
9393
userPreferencesDataSource.setBlacklistAlerts(value)
9494

95+
suspend fun setInjectEruda(value: List<String>) =
96+
userPreferencesDataSource.setInjectEruda(value)
97+
9598
suspend fun setAllowedFsModules(value: List<String>) =
9699
userPreferencesDataSource.setAllowedFsModules(value)
97100

app/src/main/kotlin/com/dergoogler/mmrl/ui/activity/webui/WebUIScreen.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ fun WebUIScreen(
114114
shell = viewModel.rootShell,
115115
)
116116
)
117+
.addPathHandler(
118+
"/mmrl/assets/",
119+
WebViewAssetLoader.AssetsPathHandler(context)
120+
)
117121
.addPathHandler(
118122
"/mmrl/",
119123
MMRLWebUIHandler(

app/src/main/kotlin/com/dergoogler/mmrl/ui/activity/webui/handlers/MMRLWebClient.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,30 @@ class MMRLWebClient(
5252
}
5353
}
5454

55+
override fun onPageFinished(view: WebView, url: String?) {
56+
val allowInjectEruda = viewModel.modId in userPrefs.injectEruda
57+
58+
if (allowInjectEruda) {
59+
view.loadUrl(
60+
"""
61+
javascript:(() => {
62+
const head = document.getElementsByTagName("head")[0];
63+
const script = document.createElement("script");
64+
script.type = "module";
65+
script.innerText = `import eruda from "https://mui.kernelsu.org/mmrl/assets/eruda.mjs";
66+
eruda.init();
67+
const sheet = new CSSStyleSheet();
68+
sheet.replaceSync('.eruda-dev-tools { padding-bottom: var(--window-inset-bottom) }');
69+
window.eruda.shadowRoot.adoptedStyleSheets.push(sheet)
70+
`;
71+
head.insertBefore(script, head.firstChild);
72+
})()
73+
"""
74+
)
75+
}
76+
super.onPageFinished(view, url)
77+
}
78+
5579
@SuppressLint("WebViewClientOnReceivedSslError")
5680
override fun onReceivedSslError(
5781
view: WebView?,

app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/settings/modulesPermissions/screens/ModulePermissonsScreen.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ import com.dergoogler.mmrl.ui.component.listItem.ListSwitchItem
1111
import com.dergoogler.mmrl.ui.providable.LocalSettings
1212
import com.dergoogler.mmrl.ui.providable.LocalUserPreferences
1313
import com.dergoogler.mmrl.viewmodel.ModulePermissionsViewModel
14+
import dev.dergoogler.mmrl.compat.core.LocalUriHandler
1415
import dev.dergoogler.mmrl.compat.ext.isNotNull
1516

1617
@Composable
1718
fun ModulePermissionsScreen(mViewModel: ModulePermissionsViewModel) {
1819
val userPreferences = LocalUserPreferences.current
1920

21+
val browser = LocalUriHandler.current
2022
val viewModel = LocalSettings.current
2123
val allowedFsModules = userPreferences.allowedFsModules
24+
val injectEruda = userPreferences.injectEruda
2225
val allowedKsuModules = userPreferences.allowedKsuModules
2326

2427
val module = mViewModel.local
@@ -28,6 +31,29 @@ fun ModulePermissionsScreen(mViewModel: ModulePermissionsViewModel) {
2831
modifier = ScaffoldDefaults.settingsScaffoldModifier,
2932
title = module.name
3033
) {
34+
ListHeader(title = R.string.debugging)
35+
36+
ListSwitchItem(
37+
enabled = module.features.webui,
38+
title = stringResource(R.string.settings_security_inject_eruda),
39+
desc= stringResource(id = R.string.settings_security_inject_eruda_desc),
40+
base = {
41+
learnMore ={
42+
browser.openUri("https://mmrl.dev/guide/webui/#javascript-api")
43+
}
44+
},
45+
checked = module.id in injectEruda,
46+
onChange = { checked ->
47+
if (checked) {
48+
val newModules = injectEruda + module.id
49+
viewModel.setInjectEruda(newModules)
50+
} else {
51+
val newModules = injectEruda.filter { it != module.id }
52+
viewModel.setInjectEruda(newModules)
53+
}
54+
}
55+
)
56+
3157
ListHeader(title = R.string.view_module_features_webui)
3258

3359
ListSwitchItem(

app/src/main/kotlin/com/dergoogler/mmrl/viewmodel/SettingsViewModel.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import com.dergoogler.mmrl.repository.ModulesRepository
1111
import com.dergoogler.mmrl.repository.UserPreferencesRepository
1212
import dagger.hilt.android.lifecycle.HiltViewModel
1313
import dev.dergoogler.mmrl.compat.viewmodel.MMRLViewModel
14-
import kotlinx.coroutines.flow.Flow
1514
import kotlinx.coroutines.flow.first
1615
import kotlinx.coroutines.launch
1716
import kotlinx.coroutines.runBlocking
@@ -211,6 +210,12 @@ class SettingsViewModel @Inject constructor(
211210
}
212211
}
213212

213+
fun setInjectEruda(value: List<String>) {
214+
viewModelScope.launch {
215+
userPreferencesRepository.setInjectEruda(value)
216+
}
217+
}
218+
214219
fun setAllowedFsModules(value: List<String>) {
215220
viewModelScope.launch {
216221
userPreferencesRepository.setAllowedFsModules(value)

0 commit comments

Comments
 (0)