nuclei/pkg/js/libs/fs/fs.go
HD Moore 5b89811b90
Support concurrent Nuclei engines in the same process (#6322)
* support for concurrent nuclei engines

* clarify LfaAllowed race

* remove unused mutex

* update LfaAllowed logic to prevent races until it can be reworked for per-execution ID

* Update pkg/templates/parser.go

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* debug tests

* debug gh action

* fixig gh template test

* using atomic

* using synclockmap

* restore tests concurrency

* lint

* wiring executionId in js fs

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Mzack9999 <mzack9999@protonmail.com>
2025-07-19 00:10:58 +05:30

112 lines
3.0 KiB
Go

package fs
import (
"context"
"os"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
)
// ListDir lists itemType values within a directory
// depending on the itemType provided
// itemType can be any one of ['file','dir',”]
// @example
// ```javascript
// const fs = require('nuclei/fs');
// // this will only return files in /tmp directory
// const files = fs.ListDir('/tmp', 'file');
// ```
// @example
// ```javascript
// const fs = require('nuclei/fs');
// // this will only return directories in /tmp directory
// const dirs = fs.ListDir('/tmp', 'dir');
// ```
// @example
// ```javascript
// const fs = require('nuclei/fs');
// // when no itemType is provided, it will return both files and directories
// const items = fs.ListDir('/tmp');
// ```
func ListDir(ctx context.Context, path string, itemType string) ([]string, error) {
executionId := ctx.Value("executionId").(string)
finalPath, err := protocolstate.NormalizePathWithExecutionId(executionId, path)
if err != nil {
return nil, err
}
values, err := os.ReadDir(finalPath)
if err != nil {
return nil, err
}
var results []string
for _, value := range values {
if itemType == "file" && value.IsDir() {
continue
}
if itemType == "dir" && !value.IsDir() {
continue
}
results = append(results, value.Name())
}
return results, nil
}
// ReadFile reads file contents within permitted paths
// and returns content as byte array
// @example
// ```javascript
// const fs = require('nuclei/fs');
// // here permitted directories are $HOME/nuclei-templates/*
// const content = fs.ReadFile('helpers/usernames.txt');
// ```
func ReadFile(ctx context.Context, path string) ([]byte, error) {
executionId := ctx.Value("executionId").(string)
finalPath, err := protocolstate.NormalizePathWithExecutionId(executionId, path)
if err != nil {
return nil, err
}
bin, err := os.ReadFile(finalPath)
return bin, err
}
// ReadFileAsString reads file contents within permitted paths
// and returns content as string
// @example
// ```javascript
// const fs = require('nuclei/fs');
// // here permitted directories are $HOME/nuclei-templates/*
// const content = fs.ReadFileAsString('helpers/usernames.txt');
// ```
func ReadFileAsString(ctx context.Context, path string) (string, error) {
bin, err := ReadFile(ctx, path)
if err != nil {
return "", err
}
return string(bin), nil
}
// ReadFilesFromDir reads all files from a directory
// and returns a string array with file contents of all files
// @example
// ```javascript
// const fs = require('nuclei/fs');
// // here permitted directories are $HOME/nuclei-templates/*
// const contents = fs.ReadFilesFromDir('helpers/ssh-keys');
// log(contents);
// ```
func ReadFilesFromDir(ctx context.Context, dir string) ([]string, error) {
files, err := ListDir(ctx, dir, "file")
if err != nil {
return nil, err
}
var results []string
for _, file := range files {
content, err := ReadFileAsString(ctx, dir+"/"+file)
if err != nil {
return nil, err
}
results = append(results, content)
}
return results, nil
}