@live-change/pattern 0.2.0 → 0.8.2
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/LICENSE.md +11 -0
- package/index.js +2 -1
- package/lib/graph.js +28 -26
- package/lib/live.js +12 -6
- package/lib/match.js +27 -0
- package/lib/relations-store.js +1 -1
- package/package.json +10 -8
- package/tests/{chain-with-expire.js → chain-with-expire.test.js} +6 -4
- package/tests/chain-with-filter.test.js +192 -0
- package/tests/{viral-loop.js → viral-loop.test.js} +1 -1
- package/.idea/$CACHE_FILE$ +0 -6
- package/.idea/$PRODUCT_WORKSPACE_FILE$ +0 -19
- package/.idea/codeStyles/Project.xml +0 -42
- package/.idea/codeStyles/codeStyleConfig.xml +0 -5
- package/.idea/misc.xml +0 -9
- package/.idea/modules.xml +0 -8
- package/.idea/workspace.xml +0 -83
- package/reactive-pattern.iml +0 -8
- /package/tests/{linked-chain-with-expire.js → linked-chain-with-expire.test.js} +0 -0
- /package/tests/{linked-simple-chain.js → linked-simple-chain.test.js} +0 -0
- /package/tests/{simple-chain.js → simple-chain.test.js} +0 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Copyright 2019-2024 Michał Łaszczewski
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
4
|
+
|
|
5
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
6
|
+
|
|
7
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
8
|
+
|
|
9
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
10
|
+
|
|
11
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/index.js
CHANGED
package/lib/graph.js
CHANGED
|
@@ -5,13 +5,13 @@ function updateGraph(event, transitions, aggregation, addToNode, addToRelation)
|
|
|
5
5
|
for(const transition of transitions) {
|
|
6
6
|
if(transition.relation && mark) mark(transition.relation)
|
|
7
7
|
const ids = aggregation.nodes(transition, event.keys)
|
|
8
|
+
console.log("TR", transition, 'KEYS', event.keys, 'IDS', ids)
|
|
8
9
|
for(let id of ids) {
|
|
9
10
|
addToNode(id, transition, event, !transition.relation)
|
|
10
11
|
if (transition.relation != null) {
|
|
11
12
|
for(const prev of transition.relation.prev) {
|
|
12
|
-
//console.log("PREV", prev, transition.relation)
|
|
13
13
|
const prevIds = aggregation.nodes(prev, transition.relation && transition.relation.keys)
|
|
14
|
-
for
|
|
14
|
+
for(const prevId of prevIds) {
|
|
15
15
|
addToRelation(id, prevId, transition, event, true)
|
|
16
16
|
addToRelation(prevId, id, transition, event, false)
|
|
17
17
|
}
|
|
@@ -69,10 +69,10 @@ const agg = {
|
|
|
69
69
|
relationEq: (transition, otherId) => (rel) => rel.to == otherId,
|
|
70
70
|
},
|
|
71
71
|
nodeElementDepth: {
|
|
72
|
-
nodes: ({ element, relation }, keys) => [element + ':' + (relation
|
|
72
|
+
nodes: ({ element, relation }, keys) => [element + ':' + (relation?.depth ?? 0)],
|
|
73
73
|
mark: (event) =>
|
|
74
74
|
(rel) => rel.depth = (rel.prev && rel.prev.length)
|
|
75
|
-
? rel.prev.reduce((a, b) => Math.max(a, b
|
|
75
|
+
? rel.prev.reduce((a, b) => Math.max(a, b?.relation?.depth ?? 0), 0) + 1
|
|
76
76
|
: 0
|
|
77
77
|
},
|
|
78
78
|
nodeElement: {
|
|
@@ -106,30 +106,32 @@ class SummaryGraphProcessor extends LiveProcessor {
|
|
|
106
106
|
this.removeCanceledRelations(canceledRelations)
|
|
107
107
|
|
|
108
108
|
await updateGraph(event, transitions, this.aggregation,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
this.graph.set(id, node)
|
|
109
|
+
(id, transition, event, start) => {
|
|
110
|
+
let node = this.graph.get(id)
|
|
111
|
+
if (!node) {
|
|
112
|
+
node = {
|
|
113
|
+
id,
|
|
114
|
+
prev: [],
|
|
115
|
+
next: [],
|
|
116
|
+
start: false
|
|
119
117
|
}
|
|
120
|
-
this.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
this.graph.set(id, node)
|
|
119
|
+
}
|
|
120
|
+
this.aggregation.addToNode(node, transition, event)
|
|
121
|
+
if(start) node.start = true
|
|
122
|
+
},
|
|
123
|
+
(fromId, toId, transition, event, prev) => {
|
|
124
|
+
let node = this.graph.get(fromId)
|
|
125
|
+
if(!node) console.log("NODE", node, fromId)
|
|
126
|
+
if(!node) throw new Error('node '+fromId+' not found when adding relation')
|
|
127
|
+
const list = (prev ? node.prev : node.next)
|
|
128
|
+
let rel = list.find(this.aggregation.relationEq(transition, toId))
|
|
129
|
+
if(!rel) {
|
|
130
|
+
rel = this.aggregation.relationFactory(transition, toId)
|
|
131
|
+
list.push(rel)
|
|
132
132
|
}
|
|
133
|
+
this.aggregation.addToRelation(rel, transition, event)
|
|
134
|
+
}
|
|
133
135
|
)
|
|
134
136
|
}
|
|
135
137
|
}
|
package/lib/live.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { parseDuration } = require('./duration.js')
|
|
2
|
+
const { eventElementMatch } = require('./match.js')
|
|
2
3
|
|
|
3
4
|
function relationDescriptors(model, source, now, relation, keys, prev, withCancel = true) {
|
|
4
5
|
let descriptors = []
|
|
@@ -45,8 +46,9 @@ function findDescriptor(that, list) {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
async function processEvent(event, model, getRelationsByEvent) {
|
|
48
|
-
const { type, keys } = event
|
|
49
|
+
const { type, keys, properties } = event
|
|
49
50
|
const nextRelations = await getRelationsByEvent(type, keys)
|
|
51
|
+
//console.log("EVENT", event, "NEXT RELATIONS", nextRelations)
|
|
50
52
|
|
|
51
53
|
let newRelations = []
|
|
52
54
|
let canceledRelations = []
|
|
@@ -58,7 +60,7 @@ async function processEvent(event, model, getRelationsByEvent) {
|
|
|
58
60
|
if(findDescriptor(relationDescriptor, canceledRelations)) continue
|
|
59
61
|
const relationModel = model.relations[relationDescriptor.relation]
|
|
60
62
|
//console.log("NEXT RELATION MODEL", relationModel)
|
|
61
|
-
const nextElements = relationModel.next.filter(id => model.elements[id]
|
|
63
|
+
const nextElements = relationModel.next.filter(id => eventElementMatch(event, model.elements[id]))
|
|
62
64
|
//console.log("NEXT ELEMENTS", nextElements)
|
|
63
65
|
if (nextElements.length > 0) {
|
|
64
66
|
if(relationModel.cancel) {
|
|
@@ -83,6 +85,7 @@ async function processEvent(event, model, getRelationsByEvent) {
|
|
|
83
85
|
if(newElements) {
|
|
84
86
|
for (const element of newElements) {
|
|
85
87
|
const elementModel = model.elements[element]
|
|
88
|
+
if(!eventElementMatch(event, elementModel)) continue
|
|
86
89
|
//console.log("NEW ELEMENT", element, elementModel)
|
|
87
90
|
let transition = { element, relation: null }
|
|
88
91
|
transitions.push(transition)
|
|
@@ -161,9 +164,10 @@ class LiveProcessor {
|
|
|
161
164
|
|
|
162
165
|
const { newRelations, canceledRelations, actions } = changes
|
|
163
166
|
|
|
164
|
-
|
|
167
|
+
/*
|
|
168
|
+
console.log("PROCESSING RESULTS:")
|
|
165
169
|
console.log("NR: ", newRelations)
|
|
166
|
-
console.log("CR: ", canceledRelations)
|
|
170
|
+
console.log("CR: ", canceledRelations)//*/
|
|
167
171
|
|
|
168
172
|
await this.applyChanges(changes, event)
|
|
169
173
|
return actions
|
|
@@ -197,8 +201,10 @@ class LiveProcessor {
|
|
|
197
201
|
}
|
|
198
202
|
|
|
199
203
|
async applyChanges({ newRelations, canceledRelations }, event) {
|
|
200
|
-
|
|
201
|
-
|
|
204
|
+
await Promise.all([
|
|
205
|
+
this.addNewRelations(newRelations),
|
|
206
|
+
this.removeCanceledRelations(canceledRelations)
|
|
207
|
+
])
|
|
202
208
|
}
|
|
203
209
|
}
|
|
204
210
|
|
package/lib/match.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function matchProperties(match, properties) {
|
|
2
|
+
for(const key in match) {
|
|
3
|
+
const value = match[key]
|
|
4
|
+
const property = properties[key]
|
|
5
|
+
if(typeof value == 'object') {
|
|
6
|
+
if(typeof property != 'object') return false
|
|
7
|
+
if(!matchProperties(value, property)) return false
|
|
8
|
+
} else {
|
|
9
|
+
if(value != property) return false
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return true
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function eventElementMatch(event, element) {
|
|
16
|
+
console.log("CHECK ELEMENT", element)
|
|
17
|
+
if(element.type != event.type) return false
|
|
18
|
+
if(element.match) {
|
|
19
|
+
console.log("MATCH PROPERTIES", event, element)
|
|
20
|
+
if(!event.properties) return false
|
|
21
|
+
if(!matchProperties(element.match, event.properties)) return false
|
|
22
|
+
}
|
|
23
|
+
console.log("ELEMENT FOUND", event, element)
|
|
24
|
+
return true
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = { eventElementMatch, matchProperties }
|
package/lib/relations-store.js
CHANGED
|
@@ -18,7 +18,7 @@ function relationsStore() {
|
|
|
18
18
|
let eventRelations = new Map() // By event and key and value
|
|
19
19
|
let eventRelationsBySource = new Map()
|
|
20
20
|
|
|
21
|
-
async function getRelations(type, keys) {
|
|
21
|
+
async function getRelations(type, keys, properties) {
|
|
22
22
|
const keyIds = eventRelationKeys(type, keys)
|
|
23
23
|
const found = keyIds.map(key => eventRelations.get(key) || []).reduce((a,b) => a.concat(b), [])
|
|
24
24
|
if(found.length == 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/pattern",
|
|
3
|
-
"version": "0.2
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "Realtime usage pattern analysis for security, analytics and gamification purposes",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,11 +10,7 @@
|
|
|
10
10
|
"type": "git",
|
|
11
11
|
"url": "git+https://github.com/live-change/pattern.git"
|
|
12
12
|
},
|
|
13
|
-
"author":
|
|
14
|
-
"email": "m8@em8.pl",
|
|
15
|
-
"name": "Michał Łaszczewski",
|
|
16
|
-
"url": "https://www.viamage.com/"
|
|
17
|
-
},
|
|
13
|
+
"author": "Michał Łaszczewski <m8@em8.pl> (https://www.viamage.com/)",
|
|
18
14
|
"license": "MIT",
|
|
19
15
|
"bugs": {
|
|
20
16
|
"url": "https://github.com/live-change/pattern/issues"
|
|
@@ -25,6 +21,12 @@
|
|
|
25
21
|
"d3-node": "^2.2.1",
|
|
26
22
|
"d3-path-arrows": "^0.4.0",
|
|
27
23
|
"d3-sankey-circular": "^0.34.0",
|
|
28
|
-
"tape": "^
|
|
29
|
-
}
|
|
24
|
+
"tape": "^5.7.4"
|
|
25
|
+
},
|
|
26
|
+
"directories": {
|
|
27
|
+
"lib": "lib",
|
|
28
|
+
"test": "tests"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [],
|
|
31
|
+
"gitHead": "53b8efc8ec7f5c1c4af33077d8fb4a8a5580f1d9"
|
|
30
32
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const test = require('tape')
|
|
2
|
-
const
|
|
2
|
+
const lcp = require('../index.js')
|
|
3
3
|
|
|
4
4
|
let model
|
|
5
5
|
|
|
@@ -7,7 +7,7 @@ test("compile fail2ban chain with expire", (t) => {
|
|
|
7
7
|
|
|
8
8
|
t.plan(2)
|
|
9
9
|
|
|
10
|
-
let { model: compiled, last } =
|
|
10
|
+
let { model: compiled, last } = lcp.chain([
|
|
11
11
|
"failed-login",
|
|
12
12
|
{ eq: "ip", expire: "2m" },
|
|
13
13
|
"failed-login"
|
|
@@ -78,8 +78,8 @@ test("compile fail2ban chain with expire", (t) => {
|
|
|
78
78
|
t.test('live processor', (t) => {
|
|
79
79
|
t.plan(4)
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
const processor = new
|
|
81
|
+
lcp.prepareModelForLive(model)
|
|
82
|
+
const processor = new lcp.LiveProcessor(model, lcp.relationsStore())
|
|
83
83
|
const ip = (Math.random()*1000).toFixed()
|
|
84
84
|
let time = 0
|
|
85
85
|
|
|
@@ -89,6 +89,8 @@ test("compile fail2ban chain with expire", (t) => {
|
|
|
89
89
|
console.log("EVT", processor.store.eventRelations)
|
|
90
90
|
console.log("TO", processor.timeouts)
|
|
91
91
|
console.log("ACTIONS", actions)
|
|
92
|
+
const relations = await processor.store.getRelations('failed-login', { ip })
|
|
93
|
+
console.log("RELATIONS", JSON.stringify(relations, null, " "))
|
|
92
94
|
if(processor.store.eventRelations.get(`["failed-login",[["ip","${ip}"]]]`)) t.pass('processed')
|
|
93
95
|
else t.fail('no reaction')
|
|
94
96
|
})
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
const test = require('tape')
|
|
2
|
+
const lcp = require('../index.js')
|
|
3
|
+
|
|
4
|
+
let model
|
|
5
|
+
|
|
6
|
+
test("compile fail2ban chain with expire", (t) => {
|
|
7
|
+
|
|
8
|
+
t.plan(3)
|
|
9
|
+
|
|
10
|
+
let { model: compiled, last } = lcp.chain([
|
|
11
|
+
{ type: "failed-authentication", match: { secretType: 'code' } },
|
|
12
|
+
"ip",
|
|
13
|
+
{ type: "failed-authentication", match: { secretType: 'code' } }
|
|
14
|
+
])
|
|
15
|
+
|
|
16
|
+
compiled.elements[last].actions = [ 'ban' ]
|
|
17
|
+
|
|
18
|
+
console.log(JSON.stringify(compiled, null, ' '))
|
|
19
|
+
|
|
20
|
+
model = compiled
|
|
21
|
+
|
|
22
|
+
t.deepEqual(model, {
|
|
23
|
+
"elements": {
|
|
24
|
+
"failed-authentication": {
|
|
25
|
+
"type": "failed-authentication",
|
|
26
|
+
"match": {
|
|
27
|
+
"secretType": "code"
|
|
28
|
+
},
|
|
29
|
+
"id": "failed-authentication",
|
|
30
|
+
"prev": [],
|
|
31
|
+
"next": [
|
|
32
|
+
"failed-authentication/ip/failed-authentication"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"failed-authentication/ip/failed-authentication": {
|
|
36
|
+
"type": "failed-authentication",
|
|
37
|
+
"match": {
|
|
38
|
+
"secretType": "code"
|
|
39
|
+
},
|
|
40
|
+
"id": "failed-authentication/ip/failed-authentication",
|
|
41
|
+
"prev": [
|
|
42
|
+
"failed-authentication/ip/failed-authentication"
|
|
43
|
+
],
|
|
44
|
+
"next": [],
|
|
45
|
+
"actions": [
|
|
46
|
+
"ban"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"relations": {
|
|
51
|
+
"failed-authentication/ip/failed-authentication": {
|
|
52
|
+
"eq": [
|
|
53
|
+
{
|
|
54
|
+
"prev": "ip",
|
|
55
|
+
"next": "ip"
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"id": "failed-authentication/ip/failed-authentication",
|
|
59
|
+
"prev": [
|
|
60
|
+
"failed-authentication"
|
|
61
|
+
],
|
|
62
|
+
"next": [
|
|
63
|
+
"failed-authentication/ip/failed-authentication"
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
t.test('live processor with second event filtered', (t) => {
|
|
70
|
+
t.plan(3)
|
|
71
|
+
|
|
72
|
+
lcp.prepareModelForLive(model)
|
|
73
|
+
const processor = new lcp.LiveProcessor(model, lcp.relationsStore())
|
|
74
|
+
const ip = (Math.random() * 1000).toFixed()
|
|
75
|
+
let time = 0
|
|
76
|
+
|
|
77
|
+
t.test('push first event', async (t) => {
|
|
78
|
+
t.plan(1)
|
|
79
|
+
const actions = await processor.processEvent({
|
|
80
|
+
id: 1, type: 'failed-authentication', keys: { ip }, properties: { secretType: 'code' }, time
|
|
81
|
+
}, 0)
|
|
82
|
+
console.log("EVT", processor.store.eventRelations)
|
|
83
|
+
console.log("TO", processor.timeouts)
|
|
84
|
+
console.log("ACTIONS", actions)
|
|
85
|
+
const relations = await processor.store.getRelations('failed-authentication', { ip })
|
|
86
|
+
console.log("RELATIONS", JSON.stringify(relations, null, " "))
|
|
87
|
+
if(processor.store.eventRelations.get(`["failed-authentication",[["ip","${ip}"]]]`)) {
|
|
88
|
+
t.pass('processed')
|
|
89
|
+
} else {
|
|
90
|
+
t.fail('no reaction')
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
t.test('push second event', async (t) => {
|
|
95
|
+
t.plan(2)
|
|
96
|
+
time += 1000
|
|
97
|
+
const actions = await processor.processEvent({
|
|
98
|
+
id: 2, type: 'failed-authentication', keys: { ip }, properties: { secretType: 'link' }, time
|
|
99
|
+
}, 0)
|
|
100
|
+
console.log("EVT", processor.store.eventRelations)
|
|
101
|
+
console.log("TO", processor.timeouts)
|
|
102
|
+
const relations = await processor.store.getRelations('failed-authentication', { ip })
|
|
103
|
+
console.log("RELATIONS", JSON.stringify(relations, null, " "))
|
|
104
|
+
console.log("ACTIONS", actions)
|
|
105
|
+
if(actions.length > 0) {
|
|
106
|
+
t.fail('actions where it should be filtered')
|
|
107
|
+
} else {
|
|
108
|
+
t.pass('event filtered')
|
|
109
|
+
}
|
|
110
|
+
if(processor.store.eventRelations.get(`["failed-authentication",[["ip","${ip}"]]]`)) {
|
|
111
|
+
t.pass('previous event exist')
|
|
112
|
+
} else {
|
|
113
|
+
t.fail('previous event not exist')
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
t.test('push third event', async (t) => {
|
|
118
|
+
t.plan(1)
|
|
119
|
+
time += 1000
|
|
120
|
+
const actions = await processor.processEvent({
|
|
121
|
+
id: 3, type: 'failed-authentication', keys: { ip }, properties: { secretType: 'code' }, time
|
|
122
|
+
}, 0)
|
|
123
|
+
console.log("ACTIONS", actions)
|
|
124
|
+
t.deepEqual(actions, ['ban'], 'actions match')
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
t.test('live processor with first event filtered', (t) => {
|
|
130
|
+
t.plan(3)
|
|
131
|
+
|
|
132
|
+
lcp.prepareModelForLive(model)
|
|
133
|
+
const processor = new lcp.LiveProcessor(model, lcp.relationsStore())
|
|
134
|
+
const ip = (Math.random() * 1000).toFixed()
|
|
135
|
+
let time = 0
|
|
136
|
+
|
|
137
|
+
t.test('push first event', async (t) => {
|
|
138
|
+
t.plan(1)
|
|
139
|
+
const actions = await processor.processEvent({
|
|
140
|
+
id: 1, type: 'failed-authentication', keys: { ip }, properties: { secretType: 'link' }, time
|
|
141
|
+
}, 0)
|
|
142
|
+
console.log("EVT", processor.store.eventRelations)
|
|
143
|
+
console.log("TO", processor.timeouts)
|
|
144
|
+
console.log("ACTIONS", actions)
|
|
145
|
+
const relations = await processor.store.getRelations('failed-authentication', { ip })
|
|
146
|
+
console.log("RELATIONS", JSON.stringify(relations, null, " "))
|
|
147
|
+
if(!processor.store.eventRelations.get(`["failed-authentication",[["ip","${ip}"]]]`)) {
|
|
148
|
+
t.pass('filtered')
|
|
149
|
+
} else {
|
|
150
|
+
t.fail('processed')
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
t.test('push second event', async (t) => {
|
|
155
|
+
t.plan(2)
|
|
156
|
+
time += 1000
|
|
157
|
+
const actions = await processor.processEvent({
|
|
158
|
+
id: 1, type: 'failed-authentication', keys: { ip }, properties: { secretType: 'code' }, time
|
|
159
|
+
}, 0)
|
|
160
|
+
console.log("EVT", processor.store.eventRelations)
|
|
161
|
+
console.log("TO", processor.timeouts)
|
|
162
|
+
console.log("ACTIONS", actions)
|
|
163
|
+
const relations = await processor.store.getRelations('failed-authentication', { ip })
|
|
164
|
+
console.log("RELATIONS", JSON.stringify(relations, null, " "))
|
|
165
|
+
if(processor.store.eventRelations.get(`["failed-authentication",[["ip","${ip}"]]]`)) {
|
|
166
|
+
t.pass('processed')
|
|
167
|
+
} else {
|
|
168
|
+
t.fail('no reaction')
|
|
169
|
+
}
|
|
170
|
+
console.log("ACTIONS", actions)
|
|
171
|
+
if(actions.length > 0) {
|
|
172
|
+
t.fail('actions where it should be filtered')
|
|
173
|
+
} else {
|
|
174
|
+
t.pass('no action')
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
t.test('push third event', async (t) => {
|
|
179
|
+
t.plan(1)
|
|
180
|
+
time += 1000
|
|
181
|
+
const actions = await processor.processEvent({
|
|
182
|
+
id: 3, type: 'failed-authentication', keys: { ip }, properties: { secretType: 'code' }, time
|
|
183
|
+
}, 0)
|
|
184
|
+
console.log("ACTIONS", actions)
|
|
185
|
+
t.deepEqual(actions, ['ban'], 'actions match')
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
|
package/.idea/$CACHE_FILE$
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="masterDetails">
|
|
4
|
-
<states>
|
|
5
|
-
<state key="ProjectJDKs.UI">
|
|
6
|
-
<settings>
|
|
7
|
-
<last-edited>10</last-edited>
|
|
8
|
-
<splitter-proportions>
|
|
9
|
-
<option name="proportions">
|
|
10
|
-
<list>
|
|
11
|
-
<option value="0.2" />
|
|
12
|
-
</list>
|
|
13
|
-
</option>
|
|
14
|
-
</splitter-proportions>
|
|
15
|
-
</settings>
|
|
16
|
-
</state>
|
|
17
|
-
</states>
|
|
18
|
-
</component>
|
|
19
|
-
</project>
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
<component name="ProjectCodeStyleConfiguration">
|
|
2
|
-
<code_scheme name="Project" version="173">
|
|
3
|
-
<option name="OTHER_INDENT_OPTIONS">
|
|
4
|
-
<value>
|
|
5
|
-
<option name="INDENT_SIZE" value="2" />
|
|
6
|
-
<option name="TAB_SIZE" value="2" />
|
|
7
|
-
</value>
|
|
8
|
-
</option>
|
|
9
|
-
<codeStyleSettings language="CSS">
|
|
10
|
-
<indentOptions>
|
|
11
|
-
<option name="INDENT_SIZE" value="2" />
|
|
12
|
-
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
13
|
-
<option name="TAB_SIZE" value="2" />
|
|
14
|
-
</indentOptions>
|
|
15
|
-
</codeStyleSettings>
|
|
16
|
-
<codeStyleSettings language="HTML">
|
|
17
|
-
<indentOptions>
|
|
18
|
-
<option name="INDENT_SIZE" value="2" />
|
|
19
|
-
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
20
|
-
<option name="TAB_SIZE" value="2" />
|
|
21
|
-
</indentOptions>
|
|
22
|
-
</codeStyleSettings>
|
|
23
|
-
<codeStyleSettings language="JSON">
|
|
24
|
-
<indentOptions>
|
|
25
|
-
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
26
|
-
<option name="TAB_SIZE" value="2" />
|
|
27
|
-
</indentOptions>
|
|
28
|
-
</codeStyleSettings>
|
|
29
|
-
<codeStyleSettings language="JavaScript">
|
|
30
|
-
<indentOptions>
|
|
31
|
-
<option name="INDENT_SIZE" value="2" />
|
|
32
|
-
<option name="TAB_SIZE" value="2" />
|
|
33
|
-
</indentOptions>
|
|
34
|
-
</codeStyleSettings>
|
|
35
|
-
<codeStyleSettings language="SCSS">
|
|
36
|
-
<indentOptions>
|
|
37
|
-
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
38
|
-
<option name="TAB_SIZE" value="2" />
|
|
39
|
-
</indentOptions>
|
|
40
|
-
</codeStyleSettings>
|
|
41
|
-
</code_scheme>
|
|
42
|
-
</component>
|
package/.idea/misc.xml
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="JavaScriptSettings">
|
|
4
|
-
<option name="languageLevel" value="ES6" />
|
|
5
|
-
</component>
|
|
6
|
-
<component name="ProjectRootManager">
|
|
7
|
-
<output url="file://$PROJECT_DIR$/out" />
|
|
8
|
-
</component>
|
|
9
|
-
</project>
|
package/.idea/modules.xml
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ProjectModuleManager">
|
|
4
|
-
<modules>
|
|
5
|
-
<module fileurl="file://$PROJECT_DIR$/reactive-pattern.iml" filepath="$PROJECT_DIR$/reactive-pattern.iml" />
|
|
6
|
-
</modules>
|
|
7
|
-
</component>
|
|
8
|
-
</project>
|
package/.idea/workspace.xml
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ChangeListManager">
|
|
4
|
-
<list default="true" id="4bcde310-3a88-4ac7-bcec-b705edb985bb" name="Default Changelist" comment="" />
|
|
5
|
-
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
|
6
|
-
<option name="SHOW_DIALOG" value="false" />
|
|
7
|
-
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
8
|
-
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
9
|
-
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
10
|
-
</component>
|
|
11
|
-
<component name="CodeStyleSettingsInfer">
|
|
12
|
-
<option name="done" value="true" />
|
|
13
|
-
</component>
|
|
14
|
-
<component name="ComposerSettings">
|
|
15
|
-
<execution>
|
|
16
|
-
<executable />
|
|
17
|
-
</execution>
|
|
18
|
-
</component>
|
|
19
|
-
<component name="FileTemplateManagerImpl">
|
|
20
|
-
<option name="RECENT_TEMPLATES">
|
|
21
|
-
<list>
|
|
22
|
-
<option value="JavaScript File" />
|
|
23
|
-
</list>
|
|
24
|
-
</option>
|
|
25
|
-
</component>
|
|
26
|
-
<component name="JsFlowSettings">
|
|
27
|
-
<service-enabled>true</service-enabled>
|
|
28
|
-
<exe-path />
|
|
29
|
-
<other-services-enabled>true</other-services-enabled>
|
|
30
|
-
<auto-save>true</auto-save>
|
|
31
|
-
</component>
|
|
32
|
-
<component name="ProjectCodeStyleSettingsMigration">
|
|
33
|
-
<option name="version" value="1" />
|
|
34
|
-
</component>
|
|
35
|
-
<component name="ProjectId" id="1UEIRU0fnQMKUQE3vydpnEMLQQ0" />
|
|
36
|
-
<component name="PropertiesComponent">
|
|
37
|
-
<property name="WebServerToolWindowFactoryState" value="false" />
|
|
38
|
-
<property name="javascript.nodejs.core.library.configured.version" value="10.17.0" />
|
|
39
|
-
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
|
40
|
-
<property name="nodejs_package_manager_path" value="npm" />
|
|
41
|
-
<property name="settings.editor.selected.configurable" value="Settings.JavaScript" />
|
|
42
|
-
</component>
|
|
43
|
-
<component name="RecentsManager">
|
|
44
|
-
<key name="MoveFile.RECENT_KEYS">
|
|
45
|
-
<recent name="$PROJECT_DIR$/.." />
|
|
46
|
-
</key>
|
|
47
|
-
<key name="CopyFile.RECENT_KEYS">
|
|
48
|
-
<recent name="$PROJECT_DIR$/tests" />
|
|
49
|
-
</key>
|
|
50
|
-
</component>
|
|
51
|
-
<component name="RunDashboard">
|
|
52
|
-
<option name="ruleStates">
|
|
53
|
-
<list>
|
|
54
|
-
<RuleState>
|
|
55
|
-
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
|
56
|
-
</RuleState>
|
|
57
|
-
<RuleState>
|
|
58
|
-
<option name="name" value="StatusDashboardGroupingRule" />
|
|
59
|
-
</RuleState>
|
|
60
|
-
</list>
|
|
61
|
-
</option>
|
|
62
|
-
</component>
|
|
63
|
-
<component name="SvnConfiguration">
|
|
64
|
-
<configuration />
|
|
65
|
-
</component>
|
|
66
|
-
<component name="TaskManager">
|
|
67
|
-
<task active="true" id="Default" summary="Default task">
|
|
68
|
-
<changelist id="4bcde310-3a88-4ac7-bcec-b705edb985bb" name="Default Changelist" comment="" />
|
|
69
|
-
<created>1574915319580</created>
|
|
70
|
-
<option name="number" value="Default" />
|
|
71
|
-
<option name="presentableId" value="Default" />
|
|
72
|
-
<updated>1574915319580</updated>
|
|
73
|
-
<workItem from="1574915325078" duration="15213000" />
|
|
74
|
-
<workItem from="1575015431540" duration="5716000" />
|
|
75
|
-
<workItem from="1575024741938" duration="3246000" />
|
|
76
|
-
<workItem from="1578040657122" duration="69000" />
|
|
77
|
-
</task>
|
|
78
|
-
<servers />
|
|
79
|
-
</component>
|
|
80
|
-
<component name="TypeScriptGeneratedFilesManager">
|
|
81
|
-
<option name="version" value="1" />
|
|
82
|
-
</component>
|
|
83
|
-
</project>
|
package/reactive-pattern.iml
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<module type="WEB_MODULE" version="4">
|
|
3
|
-
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
4
|
-
<exclude-output />
|
|
5
|
-
<content url="file://$USER_HOME$/IdeaProjects/reactive-pattern" />
|
|
6
|
-
<orderEntry type="sourceFolder" forTests="false" />
|
|
7
|
-
</component>
|
|
8
|
-
</module>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|