Core 02 path
Core 02 - Path Module¶
Basic Idea¶
File paths look different on every OS Windows uses backslashes , Linux uses forward slashes , and nobody can agree on anything path module abstracts all that garbage so your code works everywhere
path.join() vs path.resolve()¶
This is the most common confusion Both combine path segments but they behave differently
const path = require('path')
// join - concatenates with platform separator , no magic
const joined = path.join('/var', 'data', 'config.json')
// Linux: /var/data/config.json
// Windows: \var\data\config.json
// resolve - treats arguments as cd commands , returns absolute
const resolved = path.resolve('..', 'config', 'app.json')
// /home/user/project/../config/app.json -> /home/user/project/config/app.json
// resolve with absolute segment resets
const test = path.resolve('/etc', '/tmp', 'file.txt')
// /tmp/file.txt - /tmp resets the path
join is safe concatenation resolve is like mentally typing cd through each argument - if one starts with / , everything before it gets thrown away
// practical difference
const cfg1 = path.join('/app', '../../etc/passwd') // /app/../../etc/passwd (literal)
const cfg2 = path.resolve('/app', '../../etc/passwd') // /etc/passwd (resolved)
path.basename(), path.dirname(), path.extname()¶
const filepath = '/var/log/nginx/access.log'
// filenmae with extension
console.log(path.basename(filepath)) // access.log
// filenmae without extension
console.log(path.basename(filepath, '.log')) // access
// directory containing the file
console.log(path.dirname(filepath)) // /var/log/nginx
// extension only
console.log(path.extname(filepath)) // .log
These are pure string operations - they don't check if the file actually exists Use fs.stat() if you need existence verification
path.parse() and path.format()¶
const parsed = path.parse('/home/user/docs/report.pdf')
console.log(parsed)
// {
// root: '/',
// dir: '/home/user/docs',
// base: 'report.pdf',
// name: 'report',
// ext: '.pdf'
// }
// reverse - build a path from its components
const reconstructed = path.format({
root: '/',
dir: '/home/user/docs',
name: 'report',
ext: '.pdf'
})
// /home/user/docs/report.pdf
parse is the swiss army knife for breaking down paths format rebuilds them - useful when you manipulate components individually
path.normalize() and path.isAbsolute()¶
// normalize cleans up weird paths
const dirty = '/var//data/./config/../app.json'
const clean = path.normalize(dirty)
// /var/data/app.json
// is absolute check
console.log(path.isAbsolute('/etc/passwd')) // true
console.log(path.isAbsolute('./config.json')) // false
console.log(path.isAbsolute('config.json')) // false
normalize resolves . and .. segments without hitting the filesystem Always normalize user-provided paths before security checks
path.sep and path.delimiter¶
// path separator - / on Linux, \ on Windows
const segments = '/usr/local/bin'.split(path.sep)
// ['', 'usr', 'local', 'bin']
// PATH delimiter - : on Linux, ; on Windows
const pathEntries = process.env.PATH.split(path.delimiter)
// ['/usr/bin', '/usr/local/bin', ...]
These are how you write cross-platform code Never hardcode / or : in path operations - use path.sep and path.delimiter
Security: path.join + __dirname Is Not Security¶
// FALSE SECURITY - this is NOT safe
const path = require('path')
const safePath = path.join(__dirname, '../../etc/passwd')
// This resolves to the actual /etc/passwd file !!!
// REAL safest - normalize and check prefix
const baseDir = path.resolve(__dirname, '..', 'data')
function secureJoin(userInput) {
const target = path.normalize(path.join(baseDir, userInput))
if (!target.startsWith(baseDir)) {
throw new Error('path traversal detected')
}
return target
}
path.join with __dirname doesn't prevent traversal - it enables it The .. segments resolve upward regardless Always check the resolved path is still within your intended directory Another gotcha: path.normalize on Windows processes \\ as UNC paths Windows users should also check the resolved drive letter matches expectations
// Windows edge case
const malicious = 'C:\\Windows\\System32\\drivers\\etc\\hosts'
const resolved = path.resolve('D:\\app', malicious)
// C:\Windows\System32\drivers\etc\hosts - different drive!
Summary¶
joinconcatenates ,resolvemakes absoluteparseandformatlet you manipulate path components safelynormalizebefore security checks ,isAbsolutefor absolute checks- Never trust
path.join(baseDir, userInput)alone - verify the result
Prerequisites¶
next -> core_03_os.md