OK, I have to apologize, I only had a little experience using vite with
laravel and thought I knew how the minimize process worked.
In a few words, if the source code is kept the same, minimizer esbuild
(vite's default minimizer) will output the exact same file name and
content. So it wasn't as I said yesterday, that new variables and
functions names are used every time they are minimized. Meaning, the
checksum is indeed a reliable way to check for changes in a JS code. No
need to use astdiff unless you need to investigate what was changed if
the checksum don't match.
Also the reason my friends JS file and mine were different was because
I was using version 5.2.3 and he was using 5.2.2. Unfortunately, once I
installed version 5.2.2 there were still different files, but astdiff
showed, that the changes were minimal and insignificant. The file I got
is exactly the same as all other instances I have found of mobilizon
5.2.2. My friend told me his instance was not federated so maybe that's
why. I'll ask my friend if he has an idea and report back.
In any case, my experiment showed that a checksum check can in deed be
used to know if a code has not been tempered with and the instances are
using the expected JS file.
I understand Oliver's point of view, about that adding the necessary
LibreJS specifications to a website shouldn't be difficult, but I have
two main grievances with that:
1.- Some times they don't seem to be interested. I really don't know
why. It would be understandable if they were not aware of it, but
sometimes you let them know and they don't seem to be interested. Weird
that they go all the way as to license their project as GPL, but still
don't seem to care.
2.- And two, which might be even more important: passing the LibreJS
check doesn't warranty that the information given on the license and
the source location are true. If we audit upstream only, and the
instances have the same checksum, then we can warranty that the
software at the instances has been validated already as free software.
I understand this will only work for "big" projects, and not on small
ones or on small changes made by some one. In those cases it would be
acceptable to accept the word of the developer, maybe with a message
like "this is not a big project validated yet, but it follows libreJS
standards".
I just find out while writing this how LibreJS establishes what
libraries are free software from the start as Oliver mentioned. If I'm
not mistaken hashes are taken from https://cdnjs.com/libraries . That
is smart. Unfortunately, now days minimizing files is the common
practice. Unless I'm mistaken, all libraries are included in the
minimized file. I don't believe that adding them to cdnjs.com would be
practical since it's name suggest it should be only use to add
libraries and not the entire project, unless I'm mistaken.
I think my idea is quite interesting, we wouldn't need to have the
entire files in the repository, only their checksum. The only reason I
suggested the voting system is because I fear that auditing all
possible JS projects that claim to be free software would be
impossible, but users could do it them self. I don't know. It was just
an idea.
I really like the LibreJS idea and it is important to me. I know that
the LibreJS project is looking for a capable JS developer to continue.
I fear that I might not be up to the challenge, but if I ever try I'll
share my work and let you guys know. In the mean while I'll add my self
to the mailing list.
Thank you for your patience and reading me. Thank you.
El jue, 09-04-2026 a las 23:03 -0700, ariel escribió:
> I forgot to attach the file but here it is.
>
> El jue, 09-04-2026 a las 22:52 -0700, ariel escribió:
> > OK, it seems that astdiff is working as I hoped, and it did discern
> > between structural and function names changes, I was just not
> > reading
> > the data correctly.
> >
> > According to the results (which I'm attaching) the differences
> > between
> > my friends version and the one I got from my local installation are
> > only 0.8%. Most seem to be trivial. I think some might be the
> > result
> > of
> > a different version of the app (mobilizon) being use to generate
> > the
> > file. Otherwise, if the differences come from versions of
> > "minimizer"
> > is being used is a factor then this type of checks are worthless.
> >
> > It is not that I don't trust my friend. Is just that I wanted to
> > see
> > if
> > there could be a way to whitelist JS in LibreJS safely by finding
> > and
> > "easy and simple" way to do this type of checks. I'll ask my friend
> > to
> > help me find out what could have made the difference and return
> > back
> > with my findings. Thank you.
> >
> > El jue, 09-04-2026 a las 20:43 -0700, arielenter escribió:
> > > Thanks for your kind reply Oliver. I've been trying to test my
> > > idea
> > > in
> > > the case of the mobilizon web implementation. Unfortunately I
> > > didn't
> > > anticipate that the minimizing process of the javascript code
> > > generates a different result with little changes every time, for
> > > instance in the case of variable names, so a simple checksum on
> > > two
> > > generated files won't work.
> > >
> > > I'm still trying to find a way though, to be able to tell when
> > > two
> > > generated files came from the same source without changes. Right
> > > now
> > > I'm using npx js-beautify and cargo astdiff. Unfortunately,
> > > though
> > > it
> > > seems astdiff does rename variables so that they are the same,
> > > this
> > > doesn't seem to work with functions name apparently. I'll report
> > > back
> > > if I find how, or if anyone else wants to add something to the
> > > conversation, please do. Thank you.
> > >
> > > El mié, 8 abr 2026 a las 14:47, Oliver Day
> > > (<[email protected]>) escribió:
> > > >
> > > > Hi Arielenter
> > > >
> > > > Disclaimer: I'm not a libreJS developer.
> > > >
> > > > LibreJS already keeps a list of links to libraries that we know
> > > > are
> > > > free software, so keeping checksums for those files to see if
> > > > the
> > > > website is just self hosting them might be OK.
> > > >
> > > > I personally think that a voting system would be over-
> > > > complicating
> > > > things since people can already send any new library request to
> > > > the
> > > > libreJS team. Also it isn't too hard to comply with libreJS'
> > > > detection system - just a few comments in each file.
> > > >
> > > > On 2026-04-09 4:17 a.m., arielenter wrote:
> > > >
> > > > Recently a friend of mine started an instance of the following
> > > > web:
> > > >
> > > > https://framagit.org/kaihuri/mobilizon/
> > > >
> > > > It's been assured by my friend that this is free software and
> > > > I'm
> > > > sure
> > > > as well, but I noticed that it didn't pass the libreJS test. I
> > > > have
> > > > opened a request for support:
> > > >
> > > > https://framagit.org/kaihuri/mobilizon/-/work_items/1997
> > > >
> > > > Unfortunately, it seems that this page also requires non
> > > > LibreJS
> > > > standard JS unfortunately.
> > > >
> > > > Anyway, it got me thinking. Would it be possible to create a
> > > > method
> > > > to
> > > > register known, free software javascript ourselves? I was
> > > > thinking
> > > > about a database of checksums maybe?
> > > >
> > > > The reason I mention check sum is because to me it wouldn't be
> > > > enough
> > > > to accept javascript from a friend or a web site that you
> > > > trust,
> > > > but a
> > > > checksum will make it certain that the code was not tampered
> > > > with
> > > > from
> > > > the upstream.
> > > >
> > > > I think it would also be nice to have a shared database between
> > > > the
> > > > users with a voting system to establish the legitimacy of an
> > > > added
> > > > item. Anyway, I just wanted to ask for your guys' opinions, I'm
> > > > not
> > > > savvy enough to know whether or not it can be feasible or how
> > > > to
> > > > do
> > > > it.
> > > >
> > > > In the meantime what I can do is to try to run the process to
> > > > create
> > > > the final JS file from that project, do a checksum on it and
> > > > compare
> > > > it with my friend's website, and then whitelist only then on my
> > > > LibreJS. Does that sound like a sound strategy?
> > > >
> > > > Thank you, for your attention.
> > > >
> > > > --
> > > >
> > > > Oliver Day
> >
>
--- first.pretty.js
+++ third-beutiful.js
Structural similarity: 99.8%
Matched: 1947/1950 vs 1949
Changes: 2 added, 3 removed, 1 structural, 0 string-only (1946 unchanged)
=== Removed ===
--- Removed Px (first.pretty.js:51734-51741)
- function Px(e, t, n, r) {
- for (let i = n; i < e.length; i += 1) try {
- const o = r ? r.run(() => e[i](...t)) : e[i](...t);
- if (o instanceof Promise) return o.then(() => Px(e, t, i + 1, r))
- } catch (o) {
- return Promise.reject(o)
- }
- }
--- Removed vne (first.pretty.js:51743-51745)
- function vne(e, t, n) {
- if (e.length > 0) return Px(e, t, 0, Ix(n))
- }
--- Removed bne (first.pretty.js:51757-51856)
- var bne = class {
- _hooks;
- _before;
- _after;
- _deprecatedHooks;
- _deprecatedMessages;
- constructor() {
- this._hooks = {}, this._before = void 0, this._after = void 0,
this._deprecatedMessages = void 0, this._deprecatedHooks = {}, this.hook =
this.hook.bind(this), this.callHook = this.callHook.bind(this),
this.callHookWith = this.callHookWith.bind(this)
- }
- hook(e, t, n = {}) {
- if (!e || typeof t != "function") return () => {};
- const r = e;
- let i;
- for (; this._deprecatedHooks[e];) i = this._deprecatedHooks[e], e =
i.to;
- if (i && !n.allowDeprecated) {
- let o = i.message;
- o || (o = `${r} hook has been deprecated` + (i.to ? `, please use
${i.to}` : "")), this._deprecatedMessages || (this._deprecatedMessages = new
Set), this._deprecatedMessages.has(o) || (console.warn(o),
this._deprecatedMessages.add(o))
- }
- if (!t.name) try {
- Object.defineProperty(t, "name", {
- get: () => "_" + e.replace(/\W+/g, "_") + "_hook_cb",
- configurable: !0
- })
- } catch {}
- return this._hooks[e] = this._hooks[e] || [], this._hooks[e].push(t),
() => {
- t && (this.removeHook(e, t), t = void 0)
- }
- }
- hookOnce(e, t) {
- let n, r = (...i) => (typeof n == "function" && n(), n = void 0, r =
void 0, t(...i));
- return n = this.hook(e, r), n
- }
- removeHook(e, t) {
- const n = this._hooks[e];
- if (n) {
- const r = n.indexOf(t);
- r !== -1 && n.splice(r, 1), n.length === 0 && (this._hooks[e] =
void 0)
- }
- }
- deprecateHook(e, t) {
- this._deprecatedHooks[e] = typeof t == "string" ? {
- to: t
- } : t;
- const n = this._hooks[e] || [];
- this._hooks[e] = void 0;
- for (const r of n) this.hook(e, r)
- }
- deprecateHooks(e) {
- for (const t in e) this.deprecateHook(t, e[t])
- }
- addHooks(e) {
- const t = cg(e),
- n = Object.keys(t).map(r => this.hook(r, t[r]));
- return () => {
- for (const r of n) r();
- n.length = 0
- }
- }
- removeHooks(e) {
- const t = cg(e);
- for (const n in t) this.removeHook(n, t[n])
- }
- removeAllHooks() {
- this._hooks = {}
- }
- callHook(e, ...t) {
- return this.callHookWith(vne, e, t)
- }
- callHookParallel(e, ...t) {
- return this.callHookWith(gne, e, t)
- }
- callHookWith(e, t, n) {
- const r = this._before || this._after ? {
- name: t,
- args: n,
- context: {}
- } : void 0;
- this._before && zm(this._before, r);
- const i = e(this._hooks[t] ? [...this._hooks[t]] : [], n, t);
- return i instanceof Promise ? i.finally(() => {
- this._after && r && zm(this._after, r)
- }) : (this._after && r && zm(this._after, r), i)
- }
- beforeEach(e) {
- return this._before = this._before || [], this._before.push(e), () =>
{
- if (this._before !== void 0) {
- const t = this._before.indexOf(e);
- t !== -1 && this._before.splice(t, 1)
- }
- }
- }
- afterEach(e) {
- return this._after = this._after || [], this._after.push(e), () => {
- if (this._after !== void 0) {
- const t = this._after.indexOf(e);
- t !== -1 && this._after.splice(t, 1)
- }
- }
- }
- };
=== Added ===
+++ Added gne (third-beutiful.js:51732-51736)
+ function gne(e, t) {
+ const n = t.shift(),
+ r = Ix(n);
+ return e.reduce((i, o) => i.then(() => r.run(() => o(...t))),
Promise.resolve())
+ }
+++ Added yne (third-beutiful.js:51747-51840)
+ class yne {
+ constructor() {
+ this._hooks = {}, this._before = void 0, this._after = void 0,
this._deprecatedMessages = void 0, this._deprecatedHooks = {}, this.hook =
this.hook.bind(this), this.callHook = this.callHook.bind(this),
this.callHookWith = this.callHookWith.bind(this)
+ }
+ hook(t, n, r = {}) {
+ if (!t || typeof n != "function") return () => {};
+ const i = t;
+ let o;
+ for (; this._deprecatedHooks[t];) o = this._deprecatedHooks[t], t =
o.to;
+ if (o && !r.allowDeprecated) {
+ let a = o.message;
+ a || (a = `${i} hook has been deprecated` + (o.to ? `, please use
${o.to}` : "")), this._deprecatedMessages || (this._deprecatedMessages = new
Set), this._deprecatedMessages.has(a) || (console.warn(a),
this._deprecatedMessages.add(a))
+ }
+ if (!n.name) try {
+ Object.defineProperty(n, "name", {
+ get: () => "_" + t.replace(/\W+/g, "_") + "_hook_cb",
+ configurable: !0
+ })
+ } catch {}
+ return this._hooks[t] = this._hooks[t] || [], this._hooks[t].push(n),
() => {
+ n && (this.removeHook(t, n), n = void 0)
+ }
+ }
+ hookOnce(t, n) {
+ let r, i = (...o) => (typeof r == "function" && r(), r = void 0, i =
void 0, n(...o));
+ return r = this.hook(t, i), r
+ }
+ removeHook(t, n) {
+ if (this._hooks[t]) {
+ const r = this._hooks[t].indexOf(n);
+ r !== -1 && this._hooks[t].splice(r, 1), this._hooks[t].length
=== 0 && delete this._hooks[t]
+ }
+ }
+ deprecateHook(t, n) {
+ this._deprecatedHooks[t] = typeof n == "string" ? {
+ to: n
+ } : n;
+ const r = this._hooks[t] || [];
+ delete this._hooks[t];
+ for (const i of r) this.hook(t, i)
+ }
+ deprecateHooks(t) {
+ Object.assign(this._deprecatedHooks, t);
+ for (const n in t) this.deprecateHook(n, t[n])
+ }
+ addHooks(t) {
+ const n = cg(t),
+ r = Object.keys(n).map(i => this.hook(i, n[i]));
+ return () => {
+ for (const i of r.splice(0, r.length)) i()
+ }
+ }
+ removeHooks(t) {
+ const n = cg(t);
+ for (const r in n) this.removeHook(r, n[r])
+ }
+ removeAllHooks() {
+ for (const t in this._hooks) delete this._hooks[t]
+ }
+ callHook(t, ...n) {
+ return n.unshift(t), this.callHookWith(gne, t, ...n)
+ }
+ callHookParallel(t, ...n) {
+ return n.unshift(t), this.callHookWith(bne, t, ...n)
+ }
+ callHookWith(t, n, ...r) {
+ const i = this._before || this._after ? {
+ name: n,
+ args: r,
+ context: {}
+ } : void 0;
+ this._before && zm(this._before, i);
+ const o = t(n in this._hooks ? [...this._hooks[n]] : [], r);
+ return o instanceof Promise ? o.finally(() => {
+ this._after && i && zm(this._after, i)
+ }) : (this._after && i && zm(this._after, i), o)
+ }
+ beforeEach(t) {
+ return this._before = this._before || [], this._before.push(t), () =>
{
+ if (this._before !== void 0) {
+ const n = this._before.indexOf(t);
+ n !== -1 && this._before.splice(n, 1)
+ }
+ }
+ }
+ afterEach(t) {
+ return this._after = this._after || [], this._after.push(t), () => {
+ if (this._after !== void 0) {
+ const n = this._after.indexOf(t);
+ n !== -1 && this._after.splice(n, 1)
+ }
+ }
+ }
+ }
=== Structural Changes ===
@@@ function 'bne' (was 'gne') — structural (64.0%)
--- first.pretty.js:51747
+++ third-beutiful.js:51738
@@ -1,6 +1,5 @@
-function gne(e, t, n) {
- if (e.length > 0) {
+function bne(e, t) {
+ const n = t.shift(),
const r = Ix(n);
return Promise.all(e.map(i => r.run(() => i(...t))))
- }
}