158 lines
3.9 KiB
Go
Raw Normal View History

javascript protocol for scripting (includes 15+ proto libs) (#4109) * rebase js-layer PR from @ice3man543 * package restructuring * working * fix duplicated event & matcher status * fix lint error * fix response field * add new functions * multiple minor improvements * fix incorrect stats in js protocol * sort output metadata in cli * remove temp files * remove dead code * add unit and integration test * fix lint error * add jsdoclint using llm * fix error in test * add js lint using llm * generate docs of libs * llm lint * remove duplicated docs * update generated docs * update prompt in doclint * update docs * temp disable version check test * fix unit test and add retry * fix panic in it * update and move jsdocs * updated jsdocs * update docs * update container platform in test * dir restructure and adding docs * add api_reference and remove markdown docs * fix imports * add javascript design and contribution docs * add js protocol documentation * update integration test and docs * update doc ext mdx->md * minor update to docs * new integration test and more * move go libs and add docs * gen new net docs and more * final docs update * add new devtool * use fastdialer * fix build fail * use fastdialer + network sandbox support * add reserved keyword 'Port' * update Port to new syntax * misc update * always enable templatectx in js protocol * move docs to 'js-proto-docs' repo * remove scrapefuncs binary --------- Co-authored-by: sandeep <8293321+ehsandeep@users.noreply.github.com>
2023-09-16 16:02:17 +05:30
package main
import (
"bytes"
"context"
"flag"
"fmt"
"go/ast"
"go/parser"
"go/token"
"log"
"os"
"strings"
filutil "github.com/projectdiscovery/utils/file"
"github.com/sashabaranov/go-openai"
)
var sysprompt = `
data present after ---raw data--- contains raw data extracted by a parser and contains information about function
--- example ---
Name: log
Signatures: "log(msg string)"
Signatures: "log(msg map[string]interface{})"
Description: log prints given input to stdout with [JS] prefix for debugging purposes
--- end example ---
Here Name is name of function , signature[s] is actual function declaration and description is description of function
using this data for every such function generate a abstract implementation of function in javascript along with jsdoc annotations
--- example expected output---
/**
* log prints given input to stdout with [JS] prefix for debugging purposes
* log(msg string)
* log(msg map[string]interface{})
* @function
* @param {string} msg - The message to print.
*/
function log(msg) {
// implemented in go
};
--- instructions ---
ACT as helpful coding assistant and do the same for all functions present in data
`
const userPrompt = `
---raw data---
{{source}}
---new javascript---
`
var (
dir string
key string
keyfile string
out string
)
func main() {
flag.StringVar(&dir, "dir", "pkg/js/global", "directory to process")
flag.StringVar(&key, "key", "", "openai api key")
flag.StringVar(&keyfile, "keyfile", "", "openai api key file")
flag.StringVar(&out, "out", "", "output js file with declarations of all global functions")
flag.Parse()
finalKey := ""
if key != "" {
key = finalKey
}
if keyfile != "" && filutil.FileExists(keyfile) {
data, err := os.ReadFile(keyfile)
if err != nil {
log.Fatal(err)
}
finalKey = string(data)
}
if key := os.Getenv("OPENAI_API_KEY"); key != "" {
finalKey = key
}
if finalKey == "" {
log.Fatal("openai api key is not set")
}
llm := openai.NewClient(finalKey)
var buff bytes.Buffer
fset := token.NewFileSet()
pkgs, err := parser.ParseDir(fset, dir, nil, 0)
if err != nil {
fmt.Println(err)
return
}
for _, pkg := range pkgs {
for _, file := range pkg.Files {
ast.Inspect(file, func(n ast.Node) bool {
switch x := n.(type) {
case *ast.CallExpr:
if sel, ok := x.Fun.(*ast.SelectorExpr); ok {
if sel.Sel.Name == "RegisterFuncWithSignature" {
for _, arg := range x.Args {
if kv, ok := arg.(*ast.CompositeLit); ok {
for _, elt := range kv.Elts {
if kv, ok := elt.(*ast.KeyValueExpr); ok {
key := kv.Key.(*ast.Ident).Name
switch key {
case "Name", "Description":
buff.WriteString(fmt.Sprintf("%s: %s\n", key, strings.Trim(kv.Value.(*ast.BasicLit).Value, `"`)))
case "Signatures":
if comp, ok := kv.Value.(*ast.CompositeLit); ok {
for _, signature := range comp.Elts {
buff.WriteString(fmt.Sprintf("%s: %s\n", key, signature.(*ast.BasicLit).Value))
}
}
}
}
}
}
}
buff.WriteString("\n")
}
}
}
return true
})
}
}
fmt.Printf("[+] Scraped %d functions\n\n", strings.Count(buff.String(), "Name:"))
fmt.Println(buff.String())
fmt.Printf("[+] Generating jsdoc for all functions\n\n")
resp, err := llm.CreateChatCompletion(context.TODO(), openai.ChatCompletionRequest{
Model: "gpt-4",
Messages: []openai.ChatCompletionMessage{
{Role: "system", Content: sysprompt},
{Role: "user", Content: strings.ReplaceAll(userPrompt, "{{source}}", buff.String())},
},
Temperature: 0.1,
})
if err != nil {
fmt.Println(err)
return
}
if len(resp.Choices) == 0 {
fmt.Println("no choices returned")
return
}
data := resp.Choices[0].Message.Content
fmt.Println(data)
if out != "" {
if err := os.WriteFile(out, []byte(data), 0600); err != nil {
fmt.Println(err)
return
}
}
}