How to cache with manifest Node.js site - node.js

In relation with my early question of how to add manifest cache in node.js, my question now is related with how to cache the HTML generated by node.js. As we didn't have a physical file like in php (index.php) we cannot cache such kind of files.
How we can cache a "non existing" page? Just adding in cache:
CACHE MANIFEST
CACHE:
# plain files to cache
/javascripts/client.js
/stylesheets/style.css
/stylesheets/style.styl
# generated files like /
/
/content
Any idea of how to solve this problem?
Thanks!
Solution:
Add router to return the cache.manifest file with the correct mime-type:
app.get("/offline.manifest", function(req, res){
res.header("Content-Type", "text/cache-manifest");
res.end("CACHE MANIFEST");
});
Found at stackoverflow

The cache manifest list URLs that should be cached. The client accessing those urls has no knowledge whether these are static html files on top of Apache or dynamic content generated by node.js or anything else.
You are basically instructing the client:
Read my list of urls
Go through each url
Download the response and store it someplace safe
Check back on my cache.manifest if it has changed and then proceed to step 1
So as long as your data generated by node.js is reachable via a URL there is no problem in defining it as a line in the cache manifest.
And if you are worried "how will I know which urls there are" you can always generate the cache.manifest file programmatically from node.js itself -- but remember to serve the correct content-type text/cache-manifest

Related

How to host SPA files and embed too with axum and rust-embed

I'm having hard time understanding how to embed SPA (single page application) files with rust-embed and axum.
I have no trouble without rust-embed using a single line of code with axum (from here):
app.fallback(get_service(ServeDir::new("./app/static")).handle_error(error_handler))
It works because all files are correctly downloaded. But:
FIRST PROBLEM
What is missing for a properly SPA handling is the redirect on the index.html if for example the user reloads the page on a SPA nested route.
Example: I'm on the page: /home/customers which is not a file nor a dir but just a fake javascript route and if I reload the page axum gives me 404 (Not found).
SECOND PROBLEM
I need to embed those files in my final executable. In Golang this is "native" using embed: directive.
I saw that in Rust this is well done with rust-embed but I cannot complete my task for SPA.
The need is that every path typed by the user (and that is not an existent file such as .js or .css which obviously must be downloaded by the browser) leads to the "index.html" file in the root of my static dir.
If I use the example axum code I can see the route:
.route("/dist/*file", static_handler.into_service())
which has /dist/*file and I don't need that /dist because the index.html calls many files with custom paths, such as /_works, menu, images.
If I remove the dist part I get this error:
thread 'main' panicked at 'Invalid route: insertion failed due to conflict with previously registered route: /index.html'
Can you help me understand how to properly accomplish this task?
Thanks.
I had a similar issue, building with Vue and Axum/Rust.
Here's how I solved Problem one
Install the tower_http crate
use axum::routing::get_service to serve the build SPA.
//example implementation
...
//static file mounting
let assets_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("views");
let static_files_service = get_service(
ServeDir::new(assets_dir).append_index_html_on_directories(true),
)
.handle_error(|error: std::io::Error| async move {
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("Unhandled internal error: {}", error),
)
});
...
Mount the static file rendering
//mount the app routes and middleware
let app = Router::new()
.fallback(static_files_service)
.nest("/api/v1/", routes::root::router())
.layer(cors)
.layer(TraceLayer::new_for_http())
.layer(Extension(database));
Check out the full source code here. Another thing is, Axum seems to have breaking changes in subsequent versions as I found out here, so you might need to check the doc/example that corresponds to the version of Axum you are using :)

Next.JS security of directory structure and JSON secrets

I have a security question regarding the access of Next.JS directories, and their access requirements. I have a root folder that has my pages, public, src, styles, models folders. In the src folder I have a settings.json file that is a empty JavaScript object. The idea is that settings would be added to this file and accessed by api routes, to check settings that could be modified on this settings.json file... What I am wondering is if the client can actually somehow just read/access the src directory and get the settings.json file. I want to put secret key's here that way I can easily change secret keys without having to restart my server. So I could just update the secret key live, and have it applied to the settings.json file. Then the update would be live immediately and I don't have to change the environment variables and restart the server.
Is it safe to keep and use a json file in the src directory to store confidential data? If not, is there a way to keep and use a json file for this purpose?
Thanks for the help and info.
As juliomalves pointed out client code won't be able to access a directory or file that you have on the server with the exception of the public directory.
Next gives you the ability to serve static assets from [root]/public as documented here
Note: Only assets that are in the public directory at build time will be served by Next.js.
If this directory is ever renamed, these assets are no longer available from a client.
Note: Don't name the public directory anything else. The name cannot be changed and is the only directory used to serve static assets.
"I put a settings.json file right next to that .env file and required it in an api route, could the client somehow download that settings.json file without me purposely sending them the contents/file itself?"
The only way information can be served from an api route is by expressly creating a route to call res[ponse].send() (or res.json()) with data imported from that file. Api routes are not ever bundled on the client side and only ever exist on the server as noted here.
Any file inside the folder pages/api is mapped to /api/* and will be treated as an API endpoint instead of a page. They are server-side only bundles and won't increase your client-side bundle size.
"What I am wondering is if the client can actually somehow just read/access the src directory and get the settings.json file."
As noted above only assets in the /public directory are accessible as files by path. Directories are never accessible in Next as static assets. This is even pointed out in the source code.
send(req, path)
.on('directory', () => {
// We don't allow directories to be read.
const err: any = new Error('No directory access')
err.code = 'ENOENT'
reject(err)
})

How to static-serve all urls without '/' at the end except certain ones using express?

I am setting up a Node.JS application using express, and I want domain.tld/hey to serve the public/index/index.html folder on the server (also containing other files such as .css or .js files).
However, I DO NOT want domain.tld/hey/ to work (the / at the end is a problem for me) and in this case, I want to display a custom error page located at public/error/index.html on the server.
Finally, when accessing domain.tld or domain.tld/, I want to display a custom homepage located at public/home/index.html on the server.
To summerize:
domain.tld or domain.tld/ serves public/home/index.html
domain.tld/something serves public/index/index.html
domain.tld/something/ or domain.tld/some/thing serves public/error/index.html
I already tried using express.static('folder', { redirect: false }) but it doesn't display the index.html file and I can't get the other things to work.
I really don't know how to do it!
I fortunately don't have any code to show you guys as this is more a theorical problem, since I am beggining with expressjs.
Thank you very much in advance for your answers, and please don't hesistate to ask for more details if you need some!

CakePHP: how to allow public access to files in a directory besides /webroot

I want to be able to open pdfs that live in a folder at /app/somefile/file.pdf via apache like this http://mysite/app/somefile.file.pdf. I've tried adding a RewriteCond in CakePHP's .htaccess file:
RewriteCond %{REQUEST_URI} !^/app/somefolder/ - [L]
But just get a 500 error. What am I doing wrong?
Use this in your controller and use routes to access it the way you want, opening up other folders for the world is NOT a good idea
Sending files
There are times when you want to send files as responses for your requests. Prior to version 2.3 you could use Media Views to accomplish that. As of 2.3 MediaView is deprecated and you can use CakeResponse::file() to send a file as response:
public function sendFile($id) {
$file = $this->Attachment->getFile($id);
$this->response->file($file['path']);
//Return reponse object to prevent controller from trying to render a view
return $this->response;
`enter code here`}
As shown in above example as expected you have to pass the file path to the method. CakePHP will send proper content type header if it’s a known file type listed in CakeReponse::$_mimeTypes. You can add new types prior to calling CakeResponse::file() by using the CakeResponse::type() method.
If you want you can also force a file to be downloaded instead of being displayed in the browser by specifying the options:
$this->response->file($file['path'], array('download' => true, 'name' => 'foo'));
source: http://book.cakephp.org/2.0/en/controllers/request-response.html#cake-response-file
You could use an Apache alias to make the contents of that directory publicly accessible:
Alias /app/somefile /app/webroot/somefile
Place the above code in a server/virtual host config file, not .htaccess.
Make sure the web server user has read access to that directory.
you could just make a symlink to them, though your apache config may or may not be allowed to follow them.
I was able to do this buy only adding this to the .htaccess file in the root:
RewriteCond %{REQUEST_URI} !^/app/somefolder/
(My original version had a [L] which is incorrect, and that's why it wasn't working.)
Just in case anyone doesn't already know: this is not generally a secure thing to do. I have very specific reasons for doing this.

node.js - secure image file upload

We had to implement an image uploader for a node.js project. As framework we are using express.js We did it like described here: http://howtonode.org/really-simple-file-uploads
But we are not sure how to secure this image uploader. What we did so far is:
checking the file size
checking extension and header
rename the file
file is only accessible over a special route and is not in the root folder
Is this enough? We don't feel very comfortable with the following line:
// CHECKING FOR FILESIZE, EXTENSION, HEADERS
fs.readFile(req.files.displayImage.path, function (err, data) {
...
...
...
// RENAMING FILE
// SAVE FILE
...
...
...
}
Is it save to read the image this way? We are afraid, there could be malicious code in req.files.displayImage.path. Do we need to add more checks or are our checks sufficient? What attack vectors do we offer an attacker if we use the code as described?
Thank you for your advices
Tschoartschi
If you are concerned for opening malicious images on client side as posted in your comments. Try opening third party scripts and untrusted files inside a sandboxed iframe this will protect your users.

Resources