Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/catalog/loader/ai_loader.go
2070 views
1
package loader
2
3
import (
4
"bytes"
5
"encoding/json"
6
"io"
7
"net/http"
8
"os"
9
"path/filepath"
10
"strings"
11
12
"github.com/alecthomas/chroma/quick"
13
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
14
"github.com/projectdiscovery/nuclei/v3/pkg/types"
15
"github.com/projectdiscovery/retryablehttp-go"
16
pdcpauth "github.com/projectdiscovery/utils/auth/pdcp"
17
"github.com/projectdiscovery/utils/errkit"
18
)
19
20
const (
21
aiTemplateGeneratorAPIEndpoint = "https://api.projectdiscovery.io/v1/template/ai"
22
)
23
24
type AITemplateResponse struct {
25
CanRun bool `json:"canRun"`
26
Comment string `json:"comment"`
27
Completion string `json:"completion"`
28
Message string `json:"message"`
29
Name string `json:"name"`
30
TemplateID string `json:"template_id"`
31
}
32
33
func getAIGeneratedTemplates(prompt string, options *types.Options) ([]string, error) {
34
prompt = strings.TrimSpace(prompt)
35
if len(prompt) < 5 {
36
return nil, errkit.Newf("Prompt is too short. Please provide a more descriptive prompt")
37
}
38
39
if len(prompt) > 3000 {
40
return nil, errkit.Newf("Prompt is too long. Please limit to 3000 characters")
41
}
42
43
template, templateID, err := generateAITemplate(prompt)
44
if err != nil {
45
return nil, errkit.Newf("Failed to generate template: %v", err)
46
}
47
48
pdcpTemplateDir := filepath.Join(config.DefaultConfig.GetTemplateDir(), "pdcp")
49
if err := os.MkdirAll(pdcpTemplateDir, 0755); err != nil {
50
return nil, errkit.Newf("Failed to create pdcp template directory: %v", err)
51
}
52
53
templateFile := filepath.Join(pdcpTemplateDir, templateID+".yaml")
54
err = os.WriteFile(templateFile, []byte(template), 0644)
55
if err != nil {
56
return nil, errkit.Newf("Failed to generate template: %v", err)
57
}
58
59
options.Logger.Info().Msgf("Generated template available at: https://cloud.projectdiscovery.io/templates/%s", templateID)
60
options.Logger.Info().Msgf("Generated template path: %s", templateFile)
61
62
// Check if we should display the template
63
// This happens when:
64
// 1. No targets are provided (-target/-list)
65
// 2. No stdin input is being used
66
hasNoTargets := len(options.Targets) == 0 && options.TargetsFilePath == ""
67
hasNoStdin := !options.Stdin
68
69
if hasNoTargets && hasNoStdin {
70
// Display the template content with syntax highlighting
71
if !options.NoColor {
72
var buf bytes.Buffer
73
err = quick.Highlight(&buf, template, "yaml", "terminal16m", "monokai")
74
if err == nil {
75
template = buf.String()
76
}
77
}
78
options.Logger.Debug().Msgf("\n%s", template)
79
// FIXME:
80
// we should not be exiting the program here
81
// but we need to find a better way to handle this
82
os.Exit(0)
83
}
84
85
return []string{templateFile}, nil
86
}
87
88
func generateAITemplate(prompt string) (string, string, error) {
89
reqBody := map[string]string{
90
"prompt": prompt,
91
}
92
jsonBody, err := json.Marshal(reqBody)
93
if err != nil {
94
return "", "", errkit.Newf("Failed to marshal request body: %v", err)
95
}
96
97
req, err := http.NewRequest(http.MethodPost, aiTemplateGeneratorAPIEndpoint, bytes.NewBuffer(jsonBody))
98
if err != nil {
99
return "", "", errkit.Newf("Failed to create HTTP request: %v", err)
100
}
101
102
ph := pdcpauth.PDCPCredHandler{}
103
creds, err := ph.GetCreds()
104
if err != nil {
105
return "", "", errkit.Newf("Failed to get PDCP credentials: %v", err)
106
}
107
108
if creds == nil {
109
return "", "", errkit.Newf("PDCP API Key not configured, Create one for free at https://cloud.projectdiscovery.io/")
110
}
111
112
req.Header.Set("Content-Type", "application/json")
113
req.Header.Set(pdcpauth.ApiKeyHeaderName, creds.APIKey)
114
115
resp, err := retryablehttp.DefaultClient().Do(req)
116
if err != nil {
117
return "", "", errkit.Newf("Failed to send HTTP request: %v", err)
118
}
119
defer func() {
120
_ = resp.Body.Close()
121
}()
122
123
if resp.StatusCode == http.StatusUnauthorized {
124
return "", "", errkit.Newf("Invalid API Key or API Key not configured, Create one for free at https://cloud.projectdiscovery.io/")
125
}
126
127
if resp.StatusCode != http.StatusOK {
128
body, _ := io.ReadAll(resp.Body)
129
return "", "", errkit.Newf("API returned status code %d: %s", resp.StatusCode, string(body))
130
}
131
132
var result AITemplateResponse
133
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
134
return "", "", errkit.Newf("Failed to decode API response: %v", err)
135
}
136
137
if result.TemplateID == "" || result.Completion == "" {
138
return "", "", errkit.Newf("Failed to generate template")
139
}
140
141
return result.Completion, result.TemplateID, nil
142
}
143
144