@pb33f/cowboy-components 0.7.5 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/auth/login-button.d.ts +3 -0
- package/dist/components/auth/login-button.js +29 -8
- package/dist/components/auth/login-panel.d.ts +2 -1
- package/dist/components/auth/login-panel.js +3 -2
- package/dist/components/auth/oauth-login.d.ts +1 -0
- package/dist/components/auth/oauth-login.js +11 -5
- package/dist/components/editor/editor-breadcrumb.css.js +1 -1
- package/dist/components/model-renderer/rendered-node.d.ts +2 -0
- package/dist/components/model-renderer/rendered-node.js +18 -0
- package/dist/components/model-renderer/responses.d.ts +11 -0
- package/dist/components/model-renderer/responses.js +46 -0
- package/dist/components/model-tree/tree.js +1 -1
- package/dist/components/paginator/paginator.css.js +1 -1
- package/dist/components/paginator/paginator.d.ts +2 -0
- package/dist/components/paginator/paginator.js +6 -6
- package/dist/components/problems-overview/problems-overview.js +6 -0
- package/dist/components/rodeo/rodeo.js +1 -1
- package/dist/components/the-doctor/sparks.d.ts +1 -0
- package/dist/components/the-doctor/sparks.js +36 -21
- package/dist/components/the-doctor/status-bar.css.js +10 -8
- package/dist/components/the-doctor/status-bar.d.ts +2 -0
- package/dist/components/the-doctor/status-bar.js +18 -8
- package/dist/components/the-doctor/the-doctor.css.js +1 -1
- package/dist/components/the-doctor/the-doctor.d.ts +113 -120
- package/dist/components/the-doctor/the-doctor.js +141 -1735
- package/dist/components/the-doctor/upload-archive.d.ts +1 -0
- package/dist/components/the-doctor/upload-archive.js +29 -12
- package/dist/controllers/{auth.d.ts → auth-controller.d.ts} +11 -6
- package/dist/controllers/auth-controller.js +165 -0
- package/dist/controllers/broker-controller.d.ts +22 -0
- package/dist/controllers/broker-controller.js +107 -0
- package/dist/controllers/diagnostic-controller.d.ts +6 -0
- package/dist/controllers/diagnostic-controller.js +262 -0
- package/dist/controllers/docs-controller.d.ts +8 -0
- package/dist/controllers/docs-controller.js +144 -0
- package/dist/controllers/model-controller.d.ts +8 -0
- package/dist/controllers/model-controller.js +87 -0
- package/dist/controllers/node-clicker-controller.d.ts +11 -0
- package/dist/controllers/node-clicker-controller.js +362 -0
- package/dist/controllers/problem-controller.d.ts +7 -0
- package/dist/controllers/problem-controller.js +46 -0
- package/dist/controllers/rolodex-controller.d.ts +10 -0
- package/dist/controllers/rolodex-controller.js +126 -0
- package/dist/controllers/rule-controller.d.ts +19 -0
- package/dist/controllers/rule-controller.js +264 -0
- package/dist/controllers/spec-controller.d.ts +8 -0
- package/dist/controllers/spec-controller.js +78 -0
- package/dist/controllers/state-controller.d.ts +9 -0
- package/dist/controllers/state-controller.js +279 -0
- package/dist/cowboy-components.umd.cjs +768 -736
- package/dist/css/pb33f-theme.css +1 -0
- package/dist/css/shared.css.js +5 -0
- package/dist/events/doctor.d.ts +12 -0
- package/dist/events/doctor.js +4 -0
- package/dist/model/api-response.d.ts +7 -0
- package/dist/model/api-response.js +2 -0
- package/dist/services/auth-service.d.ts +1 -0
- package/dist/services/auth-service.js +28 -0
- package/dist/services/linting-service.js +11 -2
- package/dist/services/model-service.d.ts +2 -1
- package/dist/services/model-service.js +31 -5
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/dist/controllers/auth.js +0 -101
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { AllRulesetBag, CustomRulesetBag, DefaultDocument, DefaultRulesetBag, OWASPRulesetBag, RuleConfigurationBag, SessionRulesetMapBag } from "../components/the-doctor/the-doctor";
|
|
2
|
+
import { ActiveView, ProblemRuleFilterChangedManual } from "../events/doctor";
|
|
3
|
+
import { RulesetService } from "../services/ruleset-service";
|
|
4
|
+
import { ToastType } from "../model/toast";
|
|
5
|
+
import { MarkerSeverity } from "monaco-editor";
|
|
6
|
+
export class RuleController extends EventTarget {
|
|
7
|
+
constructor(doc) {
|
|
8
|
+
super();
|
|
9
|
+
this.doc = doc;
|
|
10
|
+
}
|
|
11
|
+
ruleClicked(evt) {
|
|
12
|
+
// get rule map from bag
|
|
13
|
+
const map = this.doc.sessionRulesetMapBag?.get(SessionRulesetMapBag);
|
|
14
|
+
if (map) {
|
|
15
|
+
const rule = map.rulesMap.find((r) => r.ruleId === evt.detail.ruleId);
|
|
16
|
+
if (rule) {
|
|
17
|
+
this.doc.selectedEditorTab = "ruleset";
|
|
18
|
+
this.doc.editorTabGroup.show(ActiveView.Ruleset);
|
|
19
|
+
this.doc.rulesetEditor.editor?.setPosition({ lineNumber: rule.line, column: rule.start });
|
|
20
|
+
this.doc.rulesetEditor.editor?.revealLineInCenter(rule.line);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
rulesetSaved(evt) {
|
|
25
|
+
// lint spec
|
|
26
|
+
if (this.doc.docBag) {
|
|
27
|
+
const doc = this.doc.docBag.get(DefaultDocument);
|
|
28
|
+
const config = this.doc.ruleConfigBag?.get(RuleConfigurationBag);
|
|
29
|
+
if (evt.detail.rules) {
|
|
30
|
+
this.doc.customRulesetBag?.set(CustomRulesetBag, evt.detail.rules);
|
|
31
|
+
// get ruleset config and disable everything,
|
|
32
|
+
// then enable the custom rules.
|
|
33
|
+
if (config) {
|
|
34
|
+
// extract config from the event
|
|
35
|
+
const newConfig = evt.detail.config;
|
|
36
|
+
if (newConfig && this.doc.ruleConfigBag) {
|
|
37
|
+
newConfig.returnedRuleset = evt.detail.returnedRules;
|
|
38
|
+
this.doc.ruleConfigBag?.set(RuleConfigurationBag, newConfig);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
RulesetService.getSessionRulesetAsYAML().then((yaml) => {
|
|
42
|
+
if (this.doc.selectedEditorTab == "spec") {
|
|
43
|
+
this.doc.rulesetPulse = true;
|
|
44
|
+
}
|
|
45
|
+
this.doc.rulesetEditor.setValue(yaml, true);
|
|
46
|
+
this.fetchRulesetMap();
|
|
47
|
+
});
|
|
48
|
+
// lint the spec
|
|
49
|
+
this.doc.diagnosticController.lintSpec(doc, '');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
customRulesetEnabled(event) {
|
|
54
|
+
const customRS = { rules: new Map() };
|
|
55
|
+
customRS.id = crypto.randomUUID();
|
|
56
|
+
customRS.owner = this.doc.authController.session.sessionId;
|
|
57
|
+
event.detail.rules.forEach((rule) => {
|
|
58
|
+
if (rule.rule.id != rule.ruleId) {
|
|
59
|
+
rule.rule.id = rule.ruleId;
|
|
60
|
+
}
|
|
61
|
+
customRS.rules.set(rule.ruleId, rule.rule);
|
|
62
|
+
});
|
|
63
|
+
// write state
|
|
64
|
+
this.doc.customRulesetBag?.set(CustomRulesetBag, customRS);
|
|
65
|
+
if (event.detail.ruleConfig) {
|
|
66
|
+
this.doc.ruleConfigBag?.set(RuleConfigurationBag, event.detail.ruleConfig);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
this.doc.ruleConfigBag?.reset();
|
|
70
|
+
// reset session ruleset
|
|
71
|
+
RulesetService.resetSessionRuleset(event.detail.rulesetReset).then(() => {
|
|
72
|
+
this.doc.sendToast({
|
|
73
|
+
id: crypto.randomUUID(),
|
|
74
|
+
type: ToastType.INFO,
|
|
75
|
+
body: "Ruleset has been reset to the default",
|
|
76
|
+
title: "Ruleset reset",
|
|
77
|
+
});
|
|
78
|
+
if (this.doc.docBag) {
|
|
79
|
+
const doc = this.doc.docBag.get(DefaultDocument);
|
|
80
|
+
let path = this.doc.rolodexActivePath;
|
|
81
|
+
if (path == 'root') {
|
|
82
|
+
path = "";
|
|
83
|
+
}
|
|
84
|
+
this.doc.diagnosticController.lintSpec(doc, this.doc.rolodexActivePath);
|
|
85
|
+
}
|
|
86
|
+
this.fetchSessionRulesetAsYaml().then((result) => {
|
|
87
|
+
this.doc.rulesetEditor?.setValue(result, true);
|
|
88
|
+
});
|
|
89
|
+
}).catch((e) => {
|
|
90
|
+
this.doc.sendToast({
|
|
91
|
+
id: crypto.randomUUID(),
|
|
92
|
+
type: ToastType.ERROR,
|
|
93
|
+
body: e.detail,
|
|
94
|
+
title: "Cannot reset ruleset",
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
ruleGroupClicked(event) {
|
|
100
|
+
this.doc.problemsPanel.focus();
|
|
101
|
+
const simEvent = new CustomEvent(ProblemRuleFilterChangedManual, {
|
|
102
|
+
bubbles: true,
|
|
103
|
+
composed: true,
|
|
104
|
+
detail: {
|
|
105
|
+
rule: event.detail.rule
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
this.doc.problemsPanel.focus();
|
|
109
|
+
this.doc.problemList.dispatchEvent(simEvent);
|
|
110
|
+
history.pushState({ rule: event.detail.rule }, "", `/${ActiveView.Problems}?rule=${event.detail.rule}`);
|
|
111
|
+
this.doc.controlTabGroup.show(ActiveView.Problems);
|
|
112
|
+
}
|
|
113
|
+
rulesetManuallyChanged() {
|
|
114
|
+
clearTimeout(this.doc.bounceId);
|
|
115
|
+
this.doc.bounceId = window.setTimeout(() => {
|
|
116
|
+
const ruleset = this.doc.rulesetEditor.editor?.getValue();
|
|
117
|
+
RulesetService.validateRuleset(ruleset).then((result) => {
|
|
118
|
+
// clear any problems
|
|
119
|
+
this.doc.manageRuleset.clearRuleProblems();
|
|
120
|
+
// create a new custom ruleset with a map of rules
|
|
121
|
+
let customRS = { rules: new Map() };
|
|
122
|
+
customRS.id = crypto.randomUUID();
|
|
123
|
+
customRS.owner = this.doc.authController.session.sessionId;
|
|
124
|
+
customRS.rules = new Map(Object.entries(result.rules));
|
|
125
|
+
customRS.rules.forEach((rule, id) => {
|
|
126
|
+
rule.id = id; // set the id to the key
|
|
127
|
+
});
|
|
128
|
+
// write state
|
|
129
|
+
this.doc.customRulesetBag?.set(CustomRulesetBag, customRS);
|
|
130
|
+
this.doc.customRuleset = customRS;
|
|
131
|
+
if (customRS.rules.size > 0) {
|
|
132
|
+
// rebuild the ruleset management
|
|
133
|
+
this.doc.manageRuleset.customRulesetManual = customRS;
|
|
134
|
+
}
|
|
135
|
+
this.doc.selectedEditorTab = ActiveView.Ruleset;
|
|
136
|
+
this.doc.controlTabGroup.show(ActiveView.Ruleset);
|
|
137
|
+
this.doc.rulesetEditor.setMarkers([]);
|
|
138
|
+
this.fetchRulesetMap();
|
|
139
|
+
}).catch((e) => {
|
|
140
|
+
this.doc.sendToast({
|
|
141
|
+
id: crypto.randomUUID(),
|
|
142
|
+
type: ToastType.ERROR,
|
|
143
|
+
body: e.detail,
|
|
144
|
+
title: e.title
|
|
145
|
+
});
|
|
146
|
+
console.error('unable to validate ruleset', e);
|
|
147
|
+
// process bad rules
|
|
148
|
+
const ruleErrors = e.body;
|
|
149
|
+
const markers = [];
|
|
150
|
+
ruleErrors?.forEach((err) => {
|
|
151
|
+
markers.push({
|
|
152
|
+
severity: MarkerSeverity.Error,
|
|
153
|
+
message: err.ruleError,
|
|
154
|
+
startLineNumber: err.line,
|
|
155
|
+
startColumn: err.startCol,
|
|
156
|
+
endLineNumber: err.line,
|
|
157
|
+
endColumn: err.endCol
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
// convert to JSON
|
|
161
|
+
RulesetService.convertToJSON(ruleset).then((json) => {
|
|
162
|
+
// create a new custom ruleset with a map of rules
|
|
163
|
+
let customRS = { rules: new Map() };
|
|
164
|
+
customRS.id = crypto.randomUUID();
|
|
165
|
+
customRS.owner = this.doc.authController.session.sessionId;
|
|
166
|
+
customRS.rules = new Map(Object.entries(json.rules));
|
|
167
|
+
customRS.rules.forEach((rule, id) => {
|
|
168
|
+
if (rule.id != id)
|
|
169
|
+
rule.id = id; // set the id to the key
|
|
170
|
+
});
|
|
171
|
+
this.doc.customRuleset = customRS;
|
|
172
|
+
if (customRS.rules.size > 0) {
|
|
173
|
+
// rebuild the ruleset management
|
|
174
|
+
this.doc.manageRuleset.customRulesetManual = customRS;
|
|
175
|
+
}
|
|
176
|
+
this.doc.rulesetEditor.setMarkers([]);
|
|
177
|
+
// clear any problems
|
|
178
|
+
this.doc.manageRuleset.clearRuleProblems();
|
|
179
|
+
// set problems.
|
|
180
|
+
this.doc.rulesetEditor.setMarkers(markers);
|
|
181
|
+
this.doc.manageRuleset.processBadRules(ruleErrors);
|
|
182
|
+
this.doc.controlTabGroup.show(ActiveView.Ruleset);
|
|
183
|
+
}).catch((e) => {
|
|
184
|
+
console.error("unable to convert ruleset to JSON", e);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
}, this.doc.debounceTimeRuleset);
|
|
188
|
+
}
|
|
189
|
+
fetchRulesetMap() {
|
|
190
|
+
RulesetService.getSessionRulesetMap().then((result) => {
|
|
191
|
+
this.doc.sessionRulesetMapBag?.set(SessionRulesetMapBag, result);
|
|
192
|
+
}).catch(() => {
|
|
193
|
+
console.warn("map is empty, or unavailable, Did you submit an empty ruleset?");
|
|
194
|
+
this.doc.sendToast({
|
|
195
|
+
id: crypto.randomUUID(),
|
|
196
|
+
type: ToastType.WARNING,
|
|
197
|
+
body: "map is empty, or unavailable, Did you submit an empty ruleset?",
|
|
198
|
+
title: "Issue fetching ruleset map"
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
exportJSON() {
|
|
203
|
+
let jsonRS;
|
|
204
|
+
if (this.doc.ruleConfigBag) {
|
|
205
|
+
const config = this.doc.ruleConfigBag.get(RuleConfigurationBag);
|
|
206
|
+
if (config && config.returnedRuleset) {
|
|
207
|
+
jsonRS = config.returnedRuleset;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (jsonRS) {
|
|
211
|
+
let reportData = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(jsonRS, null, 2));
|
|
212
|
+
this.doc.downloadRulesetLink.download = "ruleset.json";
|
|
213
|
+
this.doc.downloadRulesetLink.href = reportData;
|
|
214
|
+
this.doc.downloadRulesetLink.click();
|
|
215
|
+
this.doc.exportRulesetDialog.hide();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
exportYAML() {
|
|
219
|
+
RulesetService.getSessionRulesetAsYAML().then((yaml) => {
|
|
220
|
+
let reportData = "data:text/yaml;charset=utf-8," + encodeURIComponent(yaml);
|
|
221
|
+
this.doc.downloadRulesetLink.download = "ruleset.yaml";
|
|
222
|
+
this.doc.downloadRulesetLink.href = reportData;
|
|
223
|
+
this.doc.downloadRulesetLink.click();
|
|
224
|
+
this.doc.exportRulesetDialog.hide();
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
async fetchSessionRulesetAsYaml() {
|
|
228
|
+
return new Promise(async (resolve, reject) => {
|
|
229
|
+
RulesetService.getSessionRulesetAsYAML().then((result) => {
|
|
230
|
+
resolve(result);
|
|
231
|
+
}).catch((e) => {
|
|
232
|
+
console.error("cannot fetch session ruleset: ", e.title);
|
|
233
|
+
reject(e);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
async fetchAllRuleset() {
|
|
238
|
+
return new Promise(async (resolve) => {
|
|
239
|
+
RulesetService.getAllRuleset().then((result) => {
|
|
240
|
+
this.doc.allRuleset = result;
|
|
241
|
+
this.doc.allRulesetBag?.set(AllRulesetBag, result);
|
|
242
|
+
resolve(result);
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
async fetchDefaultRuleset() {
|
|
247
|
+
return new Promise(async (resolve) => {
|
|
248
|
+
RulesetService.getDefaultRuleset().then((result) => {
|
|
249
|
+
this.doc.defaultRuleset = result;
|
|
250
|
+
this.doc.defaultRulesetBag?.set(DefaultRulesetBag, result);
|
|
251
|
+
resolve(result);
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
async fetchOWASPRuleset() {
|
|
256
|
+
return new Promise(async (resolve) => {
|
|
257
|
+
RulesetService.getOWASPRuleset().then((result) => {
|
|
258
|
+
this.doc.OWASPRuleset = result;
|
|
259
|
+
this.doc.OWASPRulesetBag?.set(OWASPRulesetBag, result);
|
|
260
|
+
resolve(result);
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { TheDoctor } from "../components/the-doctor/the-doctor";
|
|
2
|
+
import { EditorClickedEvent, EditorUpdatedEvent } from "../events/doctor";
|
|
3
|
+
export declare class SpecController extends EventTarget {
|
|
4
|
+
doc: TheDoctor;
|
|
5
|
+
constructor(doc: TheDoctor);
|
|
6
|
+
specChanged(event: CustomEvent<EditorUpdatedEvent>): void;
|
|
7
|
+
specClicked(event: CustomEvent<EditorClickedEvent>): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { DefaultDocument, GraphBag, SessionRulesetMapBag } from "../components/the-doctor/the-doctor";
|
|
2
|
+
import { ActiveView } from "../events/doctor";
|
|
3
|
+
export class SpecController extends EventTarget {
|
|
4
|
+
constructor(doc) {
|
|
5
|
+
super();
|
|
6
|
+
this.doc = doc;
|
|
7
|
+
}
|
|
8
|
+
specChanged(event) {
|
|
9
|
+
const editor = this.doc.editorMap.get(event.detail.id);
|
|
10
|
+
if (editor && event.detail.id === 'ruleset-editor') {
|
|
11
|
+
this.doc.ruleController.rulesetManuallyChanged();
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (this.doc.docBag) {
|
|
15
|
+
this.doc.docBag.set(DefaultDocument, event.detail.content);
|
|
16
|
+
}
|
|
17
|
+
if (this.doc.autoDiagnose) {
|
|
18
|
+
clearTimeout(this.doc.bounceId);
|
|
19
|
+
this.doc.bounceId = window.setTimeout(() => {
|
|
20
|
+
this.doc.diagnosticController.lintSpec(event.detail.content);
|
|
21
|
+
}, this.doc.debounceTime);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
specClicked(event) {
|
|
25
|
+
this.doc.detailsDrawer.close();
|
|
26
|
+
if (this.doc.selectedEditorTab == "spec") {
|
|
27
|
+
let problemFound = false;
|
|
28
|
+
for (let i = 0; i < this.doc.problems?.length; i++) {
|
|
29
|
+
if (this.doc.problems[i].startLineNumber === event.detail.line) {
|
|
30
|
+
this.doc.problemList.lineClicked(event.detail.line, true);
|
|
31
|
+
this.doc.controlTabGroup.show(ActiveView.Problems);
|
|
32
|
+
if (this.doc.sidebarClosed) {
|
|
33
|
+
this.doc.toggleSidebar();
|
|
34
|
+
}
|
|
35
|
+
problemFound = true;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// use the graph lookup to find the node, use the graphResponse, if available if not, pull from bag
|
|
40
|
+
const graph = this.doc.graphBag?.get(GraphBag);
|
|
41
|
+
if (graph) {
|
|
42
|
+
if (graph.graphMap && event.detail.line) {
|
|
43
|
+
const nodeHash = graph.graphMap[event.detail.line];
|
|
44
|
+
if (nodeHash) {
|
|
45
|
+
this.doc.modelTree.explorerClicked(nodeHash);
|
|
46
|
+
const rendered = this.doc.renderedNodeMap.get(nodeHash);
|
|
47
|
+
if (rendered) {
|
|
48
|
+
this.doc.renderedNode.node = rendered;
|
|
49
|
+
}
|
|
50
|
+
if (!problemFound) {
|
|
51
|
+
this.doc.viewerPanel.click();
|
|
52
|
+
}
|
|
53
|
+
const n = this.doc.nodeIdHashMap.get(nodeHash);
|
|
54
|
+
if (n) {
|
|
55
|
+
this.doc.explorer.activeNode = n;
|
|
56
|
+
this.doc.explorer.equalizer.activeNode = n;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (this.doc.selectedEditorTab == ActiveView.Ruleset) {
|
|
63
|
+
// check ruleset map for the line number
|
|
64
|
+
const rulesetMap = this.doc.sessionRulesetMapBag?.get(SessionRulesetMapBag);
|
|
65
|
+
if (rulesetMap?.rulesMap) {
|
|
66
|
+
for (let i = 0; i < rulesetMap.rulesMap.length; i++) {
|
|
67
|
+
if (rulesetMap.rulesMap[i].line === event.detail.line) {
|
|
68
|
+
this.doc.controlTabGroup.show(ActiveView.Ruleset);
|
|
69
|
+
if (this.doc.sidebarClosed) {
|
|
70
|
+
this.doc.toggleSidebar();
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { TheDoctor } from "../components/the-doctor/the-doctor.js";
|
|
2
|
+
import { RuleFunctionSchema } from "../model/vacuum_rule.js";
|
|
3
|
+
export declare class StateController extends EventTarget {
|
|
4
|
+
doc: TheDoctor;
|
|
5
|
+
constructor(doc: TheDoctor);
|
|
6
|
+
loadState(): void;
|
|
7
|
+
fetchFunctions(): Promise<string[]>;
|
|
8
|
+
fetchFunctionSchema(functionId: string): Promise<RuleFunctionSchema>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { AllRulesetBag, CustomRulesetBag, DefaultDocument, DefaultRulesetBag, DiagnosticBag, DocumentProblems, FunctionsBag, FunctionsSchemaBag, GraphBag, HowToFixBag, OWASPRulesetBag, PanelStateBag, ReferenceMapBag, RolodexResponseBag, RolodexStateBag, RuleConfigurationBag, SessionRulesetMapBag, SettingsBag } from "../components/the-doctor/the-doctor.js";
|
|
2
|
+
import { ModelService } from "../services/model-service.js";
|
|
3
|
+
import { Problem } from "../model/problem.js";
|
|
4
|
+
import { RulesetService } from "../services/ruleset-service";
|
|
5
|
+
export class StateController extends EventTarget {
|
|
6
|
+
constructor(doc) {
|
|
7
|
+
super();
|
|
8
|
+
this.doc = doc;
|
|
9
|
+
}
|
|
10
|
+
loadState() {
|
|
11
|
+
// register a handler for settings bag changes.
|
|
12
|
+
this.doc.settingsBag?.onAllChanges(this.doc.settingsChanged.bind(this));
|
|
13
|
+
this.doc.settingsComponent.settingsBag = this.doc.settingsBag;
|
|
14
|
+
if (this.doc.settingsBag) {
|
|
15
|
+
this.doc.settingsChanged('', this.doc.settingsBag.get(SettingsBag));
|
|
16
|
+
}
|
|
17
|
+
this.doc.settingsComponent.bootstrap();
|
|
18
|
+
this.doc.rolodexNeedsReset = true;
|
|
19
|
+
// load the rolodex
|
|
20
|
+
if (this.doc.rolodexResponseBag) {
|
|
21
|
+
const response = this.doc.rolodexResponseBag.get(RolodexResponseBag);
|
|
22
|
+
if (response) {
|
|
23
|
+
this.doc.rolodexRoot = response.rolodexRoot;
|
|
24
|
+
this.doc.rolodexTree.isRolodex = true;
|
|
25
|
+
this.doc.rolodexTree.node = response.rolodexRoot;
|
|
26
|
+
response.rolodexRoot.treeExpanded = true;
|
|
27
|
+
this.doc.requestUpdate();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
let skipDocBag = false;
|
|
31
|
+
const checkRefMap = (key) => {
|
|
32
|
+
let refMap = this.doc.referenceMapBag?.get(ReferenceMapBag);
|
|
33
|
+
if (refMap) {
|
|
34
|
+
// TODO: replace with scehduled task to refresh the reference map
|
|
35
|
+
setTimeout(() => {
|
|
36
|
+
let refs = refMap?.references[key];
|
|
37
|
+
if (!refs) {
|
|
38
|
+
refs = refMap?.references[""]; // single file
|
|
39
|
+
}
|
|
40
|
+
if (refs) {
|
|
41
|
+
this.doc.references = refs;
|
|
42
|
+
this.doc.editor.links = refs;
|
|
43
|
+
this.doc.editor.applyLinkDecorations();
|
|
44
|
+
}
|
|
45
|
+
}, 5); // editor has not loaded yet, give it a second to breathe.
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
ModelService.fetchReferenceMap().then((result) => {
|
|
49
|
+
this.doc.references = result;
|
|
50
|
+
this.doc.editor.links = result;
|
|
51
|
+
this.doc.editor.applyLinkDecorations();
|
|
52
|
+
}).catch(() => {
|
|
53
|
+
this.doc.editor.clearDecorations();
|
|
54
|
+
this.doc.editor.clearAllMarkers();
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
if (this.doc.rolodexStateBag) {
|
|
59
|
+
const state = this.doc.rolodexStateBag.get(RolodexStateBag);
|
|
60
|
+
if (state) {
|
|
61
|
+
this.doc.rolodexActivePath = state.activePath;
|
|
62
|
+
this.doc.rolodexActiveHash = state.activeHash;
|
|
63
|
+
// load the root.
|
|
64
|
+
if (state.rootHash) {
|
|
65
|
+
this.doc.rolodexTree.pendingNavigationHash = state.rootHash;
|
|
66
|
+
}
|
|
67
|
+
if (state.rootPath) {
|
|
68
|
+
this.doc.rolodexRootPath = state.rootPath;
|
|
69
|
+
if (state.activePath) {
|
|
70
|
+
checkRefMap(state.activePath);
|
|
71
|
+
}
|
|
72
|
+
// ensure the session has a root selected
|
|
73
|
+
ModelService.selectRootPath(state.rootPath).then(() => {
|
|
74
|
+
// nothing to do.
|
|
75
|
+
}).catch((e) => {
|
|
76
|
+
console.error('could not select the root path on boot bro', e);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (state.rootHash)
|
|
80
|
+
this.doc.rolodexRootHash = state.rootHash;
|
|
81
|
+
if (state.activePath) {
|
|
82
|
+
this.doc.rolodexTree.pendingNavigationPath = state.activePath;
|
|
83
|
+
this.doc.rolodexTree.requestUpdate();
|
|
84
|
+
}
|
|
85
|
+
if (state.activeNode) {
|
|
86
|
+
// load the content of the active node into the editor
|
|
87
|
+
if (state.activeLanguage) {
|
|
88
|
+
this.doc.editor.switchLanguage(state.activeLanguage);
|
|
89
|
+
}
|
|
90
|
+
this.doc.editor.setValue(state.activeNode.instance, true);
|
|
91
|
+
skipDocBag = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
this.doc.rolodexActivePath = "root";
|
|
96
|
+
// refresh the refmap.
|
|
97
|
+
checkRefMap(this.doc.rolodexActivePath);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (this.doc.docBag && !skipDocBag) {
|
|
101
|
+
const doc = this.doc.docBag.get(DefaultDocument);
|
|
102
|
+
if (doc) {
|
|
103
|
+
this.doc.editor.setValue(doc, true);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
this.doc.problemBag = this.doc.bagManager.getBag(DocumentProblems);
|
|
107
|
+
if (this.doc.problemBag) {
|
|
108
|
+
const markers = this.doc.problemBag.get(DocumentProblems);
|
|
109
|
+
if (markers) {
|
|
110
|
+
this.doc.problems = markers;
|
|
111
|
+
for (let i = 0; i < markers.length; i++) {
|
|
112
|
+
markers[i] = Problem.reconstruct(markers[i]);
|
|
113
|
+
}
|
|
114
|
+
this.doc.rolodexController.buildRolodexResultMap(markers);
|
|
115
|
+
if (this.doc.rolodexProblemMap.size > 0 && this.doc.rolodexProblemMap.has(this.doc.rolodexActivePath)) {
|
|
116
|
+
const probs = this.doc.rolodexProblemMap.get(this.doc.rolodexActivePath);
|
|
117
|
+
if (probs) {
|
|
118
|
+
this.doc.editor.setMarkers(probs);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
this.doc.problemList.problems = markers;
|
|
122
|
+
this.doc.problemsOverview.problems = this.doc.problemList.problemItems;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
this.doc.howToFixBag = this.doc.bagManager.getBag(HowToFixBag);
|
|
126
|
+
this.doc.diagnosticBag = this.doc.bagManager.getBag(DiagnosticBag);
|
|
127
|
+
if (this.doc.diagnosticBag) {
|
|
128
|
+
const stats = this.doc.diagnosticBag.get(DiagnosticBag);
|
|
129
|
+
if (stats) {
|
|
130
|
+
this.doc.problemsOverview.statistics = stats;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// extract graph
|
|
134
|
+
if (this.doc.graphBag) {
|
|
135
|
+
const graph = this.doc.graphBag.get(GraphBag);
|
|
136
|
+
if (graph) {
|
|
137
|
+
this.doc.modelController.extractGraph(graph);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// extract panel state
|
|
141
|
+
if (this.doc.panelStateBag) {
|
|
142
|
+
const panelState = this.doc.panelStateBag.get(PanelStateBag);
|
|
143
|
+
if (panelState && panelState.explorerPanel) {
|
|
144
|
+
this.doc.splitPanelExplorer.position = panelState.explorerPanel;
|
|
145
|
+
}
|
|
146
|
+
if (panelState && panelState.rolodexPanel) {
|
|
147
|
+
if (this.doc.splitPanelRolodex) {
|
|
148
|
+
this.doc.splitPanelRolodex.position = panelState.rolodexPanel;
|
|
149
|
+
}
|
|
150
|
+
this.doc.rolodexDividerPosition = panelState.rolodexPanel;
|
|
151
|
+
}
|
|
152
|
+
if (panelState && panelState.inspectorPanel) {
|
|
153
|
+
this.doc.splitPanelInspector.position = panelState.inspectorPanel;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (!this.doc.rolodexRoot) {
|
|
157
|
+
// this.importDisabled = false;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// this.importDisabled = true;
|
|
161
|
+
}
|
|
162
|
+
// extract rulesets from bags
|
|
163
|
+
const promises = [];
|
|
164
|
+
this.doc.defaultRulesetBag = this.doc.bagManager.getBag(DefaultRulesetBag);
|
|
165
|
+
if (this.doc.defaultRulesetBag) {
|
|
166
|
+
const ruleset = this.doc.defaultRulesetBag.get(DefaultRulesetBag);
|
|
167
|
+
if (ruleset) {
|
|
168
|
+
this.doc.defaultRuleset = ruleset;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
promises.push(this.doc.ruleController.fetchDefaultRuleset());
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// OWASP ruleset
|
|
175
|
+
this.doc.OWASPRulesetBag = this.doc.bagManager.getBag(OWASPRulesetBag);
|
|
176
|
+
if (this.doc.OWASPRulesetBag) {
|
|
177
|
+
const ruleset = this.doc.OWASPRulesetBag.get(OWASPRulesetBag);
|
|
178
|
+
if (ruleset) {
|
|
179
|
+
this.doc.OWASPRuleset = ruleset;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
promises.push(this.doc.ruleController.fetchOWASPRuleset());
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// All ruleset
|
|
186
|
+
this.doc.allRulesetBag = this.doc.bagManager.getBag(AllRulesetBag);
|
|
187
|
+
if (this.doc.allRulesetBag) {
|
|
188
|
+
const ruleset = this.doc.allRulesetBag.get(AllRulesetBag);
|
|
189
|
+
if (ruleset) {
|
|
190
|
+
this.doc.allRuleset = ruleset;
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
promises.push(this.doc.ruleController.fetchAllRuleset());
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// functions
|
|
197
|
+
this.doc.functionsBag = this.doc.bagManager.getBag(FunctionsBag);
|
|
198
|
+
this.doc.functionSchemaBag = this.doc.bagManager.getBag(FunctionsSchemaBag);
|
|
199
|
+
if (this.doc.functionsBag) {
|
|
200
|
+
const functions = this.doc.functionsBag.get(FunctionsBag);
|
|
201
|
+
if (functions) {
|
|
202
|
+
this.doc.functions = functions;
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
promises.push(this.fetchFunctions());
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// custom ruleset
|
|
209
|
+
this.doc.customRulesetBag = this.doc.bagManager.getBag(CustomRulesetBag);
|
|
210
|
+
if (this.doc.customRulesetBag) {
|
|
211
|
+
const ruleset = this.doc.customRulesetBag.get(CustomRulesetBag);
|
|
212
|
+
if (ruleset) {
|
|
213
|
+
this.doc.customRuleset = ruleset;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
// create rule configuration bag
|
|
217
|
+
this.doc.ruleConfigBag = this.doc.bagManager.getBag(RuleConfigurationBag);
|
|
218
|
+
// create rule configuration bag
|
|
219
|
+
this.doc.sessionRulesetMapBag = this.doc.bagManager.getBag(SessionRulesetMapBag);
|
|
220
|
+
// fire off all network requests, then configure the ruleset management.
|
|
221
|
+
Promise.all(promises).then(() => {
|
|
222
|
+
// configure rule management
|
|
223
|
+
this.doc.manageRuleset.defaultRuleset = this.doc.defaultRuleset;
|
|
224
|
+
this.doc.manageRuleset.owaspRuleset = this.doc.OWASPRuleset;
|
|
225
|
+
this.doc.manageRuleset.allRuleset = this.doc.allRuleset;
|
|
226
|
+
this.doc.manageRuleset.functions = this.doc.functions;
|
|
227
|
+
const config = this.doc.ruleConfigBag?.get(RuleConfigurationBag);
|
|
228
|
+
if (config) {
|
|
229
|
+
this.doc.manageRuleset.rulesetConfig = config;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
this.doc.manageRuleset.rulesetConfig = { ruleMapping: new Map(), allRulesSwitch: true };
|
|
233
|
+
}
|
|
234
|
+
setTimeout(() => {
|
|
235
|
+
this.doc.manageRuleset.buildRulesets();
|
|
236
|
+
if (this.doc.customRuleset && this.doc.customRuleset.rules.size > 0) {
|
|
237
|
+
this.doc.manageRuleset.customRuleset = this.doc.customRuleset;
|
|
238
|
+
}
|
|
239
|
+
this.doc.ruleController.fetchSessionRulesetAsYaml().then((result) => {
|
|
240
|
+
this.doc.rulesetEditor?.setValue(result, true);
|
|
241
|
+
this.doc.ruleController.fetchRulesetMap();
|
|
242
|
+
}).catch((e) => {
|
|
243
|
+
this.doc.platformUnavailable(e);
|
|
244
|
+
});
|
|
245
|
+
}, 50);
|
|
246
|
+
});
|
|
247
|
+
// refresh state for how to fix.
|
|
248
|
+
this.doc.docsController.fetchDocs();
|
|
249
|
+
}
|
|
250
|
+
async fetchFunctions() {
|
|
251
|
+
return new Promise(async (resolve) => {
|
|
252
|
+
RulesetService.getFunctions().then((result) => {
|
|
253
|
+
this.doc.functions = result;
|
|
254
|
+
this.doc.functionsBag?.set(FunctionsBag, result);
|
|
255
|
+
// extract schemas for each function
|
|
256
|
+
const promises = [];
|
|
257
|
+
result.forEach((functionId) => {
|
|
258
|
+
promises.push(this.fetchFunctionSchema(functionId));
|
|
259
|
+
});
|
|
260
|
+
Promise.all(promises).then(() => {
|
|
261
|
+
resolve(result);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
async fetchFunctionSchema(functionId) {
|
|
267
|
+
return new Promise(async (resolve) => {
|
|
268
|
+
RulesetService.getFunctionSchema(functionId).then((result) => {
|
|
269
|
+
let m = this.doc.functionSchemaBag?.get(FunctionsSchemaBag);
|
|
270
|
+
if (!m) {
|
|
271
|
+
m = new Map();
|
|
272
|
+
}
|
|
273
|
+
m.set(functionId, result);
|
|
274
|
+
this.doc.functionSchemaBag?.set(FunctionsSchemaBag, m);
|
|
275
|
+
resolve(result);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|