How does a node find the active chain? Let's say a user joins the Bitcoin network and downloads the latest state of the blockchain (all blocks, which includes the forks/uncles). How does this user find/determine the active blockchain on which they should build upon? I'm not asking about difficulty levels or the amount of work that gets put into the chain, but as to how this one user finds that longest chain and is sure that there are no more longer chains.

I imagine the simple (and only?) way to do this would be to check every single block the user has, and then start building upon the one which has the most work put into it. However, since nodes also store the numerous forks, evaluating every single block and its "path" throughout Bitcoin's existence is likely to take a while (and continue to take longer as time goes on).

A potential 'shortcut' would be to simply look up recent blocks, eg. search for blocks that were submitted in the last 48 hours, and then just take the longest valid chain from there, but then how would one decide on a particular timeframe? (24h? 48? last week? last month?) It would still in theory be possible that the current longest chain has been published a long time ago and other nodes are acting maliciously by trying to ignore it, so this approach doesn't seem valid in my opinion.

I know Bitcoin uses LevelDB to store metadata about blocks for quick look up, which would help speed up the evaluation of all the blocks, but is there are more pragmatic approach that Bitcoin's code takes?

Also, is this evaluation done from scratch (ie. from the genesis block) each time the user boots up, or is the information about the longest chain stored somewhere on disk for quick future retrieval when the user rejoins?
When a new node joins the network, it will look up nodes from the DNS seeds. It'll reach out to multiple nodes it hears about and ask them for more peers in turn.
The new node asks each of their peers for their best chaintip and then starts sychronizing the headers of the best chaintip it hears about first. A block header is only 80 bytes (tiny in comparison to complete blocks) but already allows checking that all the blocks on that chain are connected and that the blocks are meeting the difficulty criteria.

From then on, the node verifies each block in order to validate that the consensus rules were followed. If the best chaintip they were following is found to be injuring any consensus rules, the first block to be invalid is discarded and the peers that follow this chain disconnected. The best chaintip from that point on is found instead is found by querying the remaining (rule-compliant) peers. Finally, the node will discover the valid chain with the most accumulated difficulty.  

Each release of Bitcoin Core sets a default value for the assumevalid parameter to a block that recently preceded the release. When synchronizing up to that block, nodes using assumevalid will assume that the history up to that block is valid. They will still calculate all the UTXO set transitions and check difficulty everywhere, but will not check signatures on transactions up to that block.