[GH-ISSUE #93] Serve libraries locally #37

Closed
opened 2026-02-27 08:14:53 +03:00 by kerem · 14 comments
Owner

Originally created by @kaysond on GitHub (Nov 27, 2021).
Original GitHub issue: https://github.com/lldap/lldap/issues/93

Right now all of the below libraries are pointing to cdns. For people like me who run a reverse proxy with some security headers, this can get blocked.

github.com/nitnelave/lldap@5b5395103a/app/index.html (L8-L24)

Specifically, I set Content-Security-Policy: default-src 'self' 'unsafe-inline', which prevents backend services from loading resources from external sites as a security measure.

Would you be open to a PR that adds these libs to the repo and serves them locally? I'm thinking we should add a app/static directory and serve all static files from there (we can also then add a COPY /app/app/static to the dockerfile so nothing gets forgotten)

Originally created by @kaysond on GitHub (Nov 27, 2021). Original GitHub issue: https://github.com/lldap/lldap/issues/93 Right now all of the below libraries are pointing to cdns. For people like me who run a reverse proxy with some security headers, this can get blocked. https://github.com/nitnelave/lldap/blob/5b5395103ae56ebbea841be76c000b8b243895dc/app/index.html#L8-L24 Specifically, I set `Content-Security-Policy: default-src 'self' 'unsafe-inline'`, which prevents backend services from loading resources from external sites as a security measure. Would you be open to a PR that adds these libs to the repo and serves them locally? I'm thinking we should add a `app/static` directory and serve all static files from there (we can also then add a `COPY /app/app/static` to the dockerfile so nothing gets forgotten)
kerem 2026-02-27 08:14:53 +03:00
Author
Owner

@nitnelave commented on GitHub (Nov 27, 2021):

Hmmm... I'd rather avoid having a copy of the libraries in the repository. However, I'm open to a PR that adds a main_static.html and sets up the Dockerfile to copy the main_static and download the files locally. Would that work for you?

<!-- gh-comment-id:980788157 --> @nitnelave commented on GitHub (Nov 27, 2021): Hmmm... I'd rather avoid having a copy of the libraries in the repository. However, I'm open to a PR that adds a `main_static.html` and sets up the Dockerfile to copy the main_static and download the files locally. Would that work for you?
Author
Owner

@kaysond commented on GitHub (Nov 27, 2021):

I think that's smarter actually. We could add ARGs for the versions of the libraries.

What would be in main_static.html?

<!-- gh-comment-id:980789218 --> @kaysond commented on GitHub (Nov 27, 2021): I think that's smarter actually. We could add `ARG`s for the versions of the libraries. What would be in `main_static.html`?
Author
Owner

@nitnelave commented on GitHub (Nov 27, 2021):

Same as main.html, but referencing the static folder. Basically, if you run the project from source, it'll use the dynamic, CDN libraries, and if you run it from docker it'll use the static/ folder.

<!-- gh-comment-id:980793842 --> @nitnelave commented on GitHub (Nov 27, 2021): Same as `main.html`, but referencing the static folder. Basically, if you run the project from source, it'll use the dynamic, CDN libraries, and if you run it from docker it'll use the `static/` folder.
Author
Owner

@JaneJeon commented on GitHub (Nov 28, 2021):

What’s stopping you from basically webpack/rollup’ing all of the libraries into the bundle?

<!-- gh-comment-id:980830066 --> @JaneJeon commented on GitHub (Nov 28, 2021): What’s stopping you from basically webpack/rollup’ing all of the libraries into the bundle?
Author
Owner

@nitnelave commented on GitHub (Nov 28, 2021):

I'd like to avoid making the bundle bigger if possible. That way the logic of the spa can start before the fonts and css are loaded, which should give a faster page load.

Also, I don't know what I'm doing with roll-up :)

<!-- gh-comment-id:981135274 --> @nitnelave commented on GitHub (Nov 28, 2021): I'd like to avoid making the bundle bigger if possible. That way the logic of the spa can start before the fonts and css are loaded, which should give a faster page load. Also, I don't know what I'm doing with roll-up :)
Author
Owner

@JaneJeon commented on GitHub (Nov 28, 2021):

@nitnelave that's the neat thing about rollup or webpack or any of these "bundlers" (I should know this, javascript is my language of choice) - they don't necessarily have to bundle it all into one big file. In fact, the more common thing to do in production (and I believe it is the default for webpack though I am not sure for rollup) is to chunk them (typically, you'll see a whooooole bunch of tiny little JS files in a folder, and you serve that folder, not the singular JS file), so that ONLY the needed parts are loaded when they are requested, so that the MINIMUM amount of JS is even served from the backend in the first place.

You need to try it, and this is the "best practice" used in the industry. @kaysond

For more information, read this: https://medium.com/rollup/rollup-now-has-code-splitting-and-we-need-your-help-46defd901c82 and this: https://rollupjs.org/guide/en/#code-splitting

<!-- gh-comment-id:981154265 --> @JaneJeon commented on GitHub (Nov 28, 2021): @nitnelave that's the neat thing about rollup or webpack or any of these "bundlers" (I should know this, javascript is my language of choice) - they don't necessarily have to bundle it all into one big file. In fact, the more common thing to do in production (and I believe it is the _default_ for webpack though I am not sure for rollup) is to chunk them (typically, you'll see a whooooole bunch of tiny little JS files in a folder, and you serve that _folder_, not the singular JS file), so that ONLY the needed parts are loaded when they are requested, so that the MINIMUM amount of JS is even served from the backend in the first place. You need to try it, and this is the "best practice" used in the industry. @kaysond For more information, read this: https://medium.com/rollup/rollup-now-has-code-splitting-and-we-need-your-help-46defd901c82 and this: https://rollupjs.org/guide/en/#code-splitting
Author
Owner

@nitnelave commented on GitHub (Nov 28, 2021):

Hmm, after reading both of your links, I see the point of chunk splitting, but I don't think it's useful for our project here:

  • all the code is in one WASM file with no modules and (almost) no js dependencies, and it can't realistically get split up because it's an SPA.
  • the resources that we want to load separately are the css and bootstrap js, which we know the user will need, just that the page can get rendered without so we shouldn't block on it. That can easily be achieved by HTML, which is what we're doing here.
  • Since the lazy resources are already split up and potentially cached, I don't see the point of including them in the roll-up: we'd be reimplementing what already exists with simpler tools (HTML).

It sounds like chunk splitting has its place in a dynamic JS project with many dependencies and independent modules, but I don't think it works with the WASM produced by Rust.

<!-- gh-comment-id:981171292 --> @nitnelave commented on GitHub (Nov 28, 2021): Hmm, after reading both of your links, I see the point of chunk splitting, but I don't think it's useful for our project here: - all the code is in one WASM file with no modules and (almost) no js dependencies, and it can't realistically get split up because it's an SPA. - the resources that we want to load separately are the css and bootstrap js, which *we know* the user will need, just that the page can get rendered without so we shouldn't block on it. That can easily be achieved by HTML, which is what we're doing here. - Since the lazy resources are already split up and potentially cached, I don't see the point of including them in the roll-up: we'd be reimplementing what already exists with simpler tools (HTML). It sounds like chunk splitting has its place in a dynamic JS project with many dependencies and independent modules, but I don't think it works with the WASM produced by Rust.
Author
Owner

@JaneJeon commented on GitHub (Nov 29, 2021):

The idea is you chunk not the rust part, but the additional libraries part which are currently being served over CDN. @nitnelave

<!-- gh-comment-id:981340451 --> @JaneJeon commented on GitHub (Nov 29, 2021): The idea is you chunk not the _rust_ part, but the _additional libraries_ part which are currently being served over CDN. @nitnelave
Author
Owner

@nitnelave commented on GitHub (Nov 29, 2021):

Yes, but as I said we don't have optional dependencies: we know that the libraries (bootstrap JS and that's it) will be used on the page, so we wouldn't benefit from delaying the request until they're called. It's better to request them from the beginning but not block on them, which is already what we're doing.

<!-- gh-comment-id:981342692 --> @nitnelave commented on GitHub (Nov 29, 2021): Yes, but as I said we don't have optional dependencies: we know that the libraries (bootstrap JS and that's it) will be used on the page, so we wouldn't benefit from delaying the request until they're called. It's better to request them from the beginning but not block on them, which is already what we're doing.
Author
Owner

@JaneJeon commented on GitHub (Nov 29, 2021):

Gotcha. I think I see the problem here. While in JS land you would naturally be able to split code via the require/import, Because the Rust code doesn’t directly import any of these libraries, I’m guessing webpack/rollup wouldn’t even be aware when to call “hey get this library”, right?

That IS quite a tricky issue; I have assumed up to this point from the perspective of a JS frontend where you typically have an entrypoint and “load” additional things via importing them.

So that is a no-go on the code splitting, I guess. What about serving the libraries themselves locally anyway? (i.e. instead of just GET /bundle.js, you have GET /bundle.js and GET /libs/$x)? That wouldn’t involve code splitting, and while it IS an additional complexity to handle (one that would have to be scoped out & researched further), it must be noted that there is an inherent security risk with loading libraries from CDNs, which are:

  1. out of your control
  2. can and DO get hacked, which would allow for essentially full reign over your frontend (XSS), from which it could pick up/leak your credentials and whatnot

I guess the core of the issue is that the “main” code is actually Rust compiled down to WASM in a JS file, not actual JS, but due to the reasons I’ve outlined above I think even an “alternative” approach like the one I’ve proposed (I’m sure there are other ways to skin the cat) are worth the time investment.

<!-- gh-comment-id:981687612 --> @JaneJeon commented on GitHub (Nov 29, 2021): Gotcha. I think I see the problem here. While in JS land you would naturally be able to split code via the `require`/`import`, Because the Rust code doesn’t directly import any of these libraries, I’m guessing webpack/rollup wouldn’t even be _aware_ when to call “hey get this library”, right? That IS quite a tricky issue; I have assumed up to this point from the perspective of a JS frontend where you typically have an entrypoint and “load” additional things via importing them. So that is a no-go on the code splitting, I guess. What about serving the libraries themselves locally anyway? (i.e. instead of just `GET /bundle.js`, you have `GET /bundle.js` and `GET /libs/$x`)? That wouldn’t involve code splitting, and while it IS an additional complexity to handle (one that would have to be scoped out & researched further), it must be noted that there is an inherent security risk with loading libraries from CDNs, which are: 1. out of your control 2. can and DO get hacked, which would allow for essentially full reign over your frontend (XSS), from which it could pick up/leak your credentials and whatnot I guess the core of the issue is that the “main” code is actually Rust compiled down to WASM in a JS file, not _actual_ JS, but due to the reasons I’ve outlined above I think even an “alternative” approach like the one I’ve proposed (I’m sure there are other ways to skin the cat) are worth the time investment.
Author
Owner

@nitnelave commented on GitHub (Nov 29, 2021):

Kayson's PR addresses the "serving locally" part, at least with regard to reverse proxies and security headers. It makes it easy for anyone to replace the distributed libraries with their own.

For the questions of control and security concerns, that's the role of the checksums, to make sure that what you downloaded is what you expected. Some libraries already have checksums here, and I'm not opposed to adding checksums to the others. Would you like to do a PR adding them?

<!-- gh-comment-id:981717106 --> @nitnelave commented on GitHub (Nov 29, 2021): Kayson's PR addresses the "serving locally" part, at least with regard to reverse proxies and security headers. It makes it easy for anyone to replace the distributed libraries with their own. For the questions of control and security concerns, that's the role of the checksums, to make sure that what you downloaded is what you expected. Some libraries already have checksums here, and I'm not opposed to adding checksums to the others. Would you like to do a PR adding them?
Author
Owner

@kaysond commented on GitHub (Nov 29, 2021):

For the questions of control and security concerns, that's the role of the checksums, to make sure that what you downloaded is what you expected. Some libraries already have checksums here, and I'm not opposed to adding checksums to the others. Would you like to do a PR adding them?

I can add hashes for the rest of the libs to my PR. The only reason I didn't before is because the hashes aren't supplied by the devs for the remainder so we'd have to trust the download

<!-- gh-comment-id:981732946 --> @kaysond commented on GitHub (Nov 29, 2021): > For the questions of control and security concerns, that's the role of the checksums, to make sure that what you downloaded is what you expected. Some libraries already have checksums here, and I'm not opposed to adding checksums to the others. Would you like to do a PR adding them? I can add hashes for the rest of the libs to my PR. The only reason I didn't before is because the hashes aren't supplied by the devs for the remainder so we'd have to trust the download
Author
Owner

@nitnelave commented on GitHub (Nov 29, 2021):

Unless we want to audit all the dependencies ourselves, I'd say that it's fair to assume that there is no hack of these famous CDNs, of these famous libraries, right now. If it turns out there was a hack then the hashes will fail once fixed and/or we'll hear about it. Anyway, given the risk profile of this project, it's an acceptable trade-off.

<!-- gh-comment-id:981748933 --> @nitnelave commented on GitHub (Nov 29, 2021): Unless we want to audit all the dependencies ourselves, I'd say that it's fair to assume that there is no hack *of these famous CDNs*, *of these famous libraries*, *right now*. If it turns out there was a hack then the hashes will fail once fixed and/or we'll hear about it. Anyway, given the risk profile of this project, it's an acceptable trade-off.
Author
Owner

@nitnelave commented on GitHub (Nov 30, 2021):

Fixed by #96 .

<!-- gh-comment-id:983126993 --> @nitnelave commented on GitHub (Nov 30, 2021): Fixed by #96 .
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/lldap-lldap#37
No description provided.