package javascript
import (
"context"
"io"
"path/filepath"
"strings"
"github.com/xmirrorsecurity/opensca-cli/v3/opensca/common"
"github.com/xmirrorsecurity/opensca-cli/v3/opensca/model"
"github.com/xmirrorsecurity/opensca-cli/v3/opensca/sca/filter"
)
type Sca struct{}
func (sca Sca) Language() model.Language {
return model.Lan_JavaScript
}
func (sca Sca) Filter(relpath string) bool {
return filter.JavaScriptPackageJson(relpath) ||
filter.JavaScriptPackageLock(relpath) ||
filter.JavaScriptYarnLock(relpath)
}
func (sca Sca) Sca(ctx context.Context, parent *model.File, files []*model.File, call model.ResCallback) {
jsonMap := map[string]*PackageJson{}
jsonNameMap := map[string]*PackageJson{}
lockMap := map[string]*PackageLock{}
nodeMap := map[string]*PackageJson{}
yarnMap := map[string]map[string]*YarnLock{}
for _, f := range files {
dir := filepath.Dir(strings.ReplaceAll(f.Relpath(), `\`, `/`))
if filter.JavaScriptYarnLock(f.Relpath()) {
yarnMap[dir] = ParseYarnLock(f)
}
if filter.JavaScriptPackageJson(f.Relpath()) {
var js *PackageJson
f.OpenReader(func(reader io.Reader) {
js = readJson[PackageJson](reader)
if js == nil {
return
}
if js.Dependencies == nil {
js.Dependencies = map[string]string{}
}
for k, v := range js.PeerDependencies {
js.Dependencies[k] = v
}
js.File = f
if strings.Contains(f.Relpath(), "node_modules") {
nodeMap[dir] = js
} else {
jsonMap[dir] = js
jsonNameMap[js.Name] = js
}
})
}
if filter.JavaScriptPackageLock(f.Relpath()) {
f.OpenReader(func(reader io.Reader) {
lock := readJson[PackageLock](reader)
if lock == nil {
return
}
lockMap[dir] = lock
})
}
}
for dir, js := range jsonMap {
if lock, ok := lockMap[dir]; ok {
call(js.File, ParsePackageJsonWithLock(js, lock))
continue
}
if js.File != nil {
if yarn, ok := yarnMap[dir]; ok {
call(js.File, ParsePackageJsonWithYarnLock(js, yarn))
continue
}
}
select {
case <-ctx.Done():
return
default:
}
call(js.File, ParsePackageJsonWithNode(js, nodeMap, jsonNameMap))
}
}
var defaultNpmRepo = []common.RepoConfig{
{Url: "https://r.cnpmjs.org/"},
}
func RegisterNpmRepo(repos ...common.RepoConfig) {
newRepo := common.TrimRepo(repos...)
if len(newRepo) > 0 {
defaultNpmRepo = newRepo
}
}