mirror of
https://github.com/valitydev/fraudo.git
synced 2024-11-06 01:45:16 +00:00
Add catch exception and change readme (#8)
* Add catch exception and change readme * Add get current amount * Delete from country field check
This commit is contained in:
parent
65f5f33836
commit
d479347a90
2
.gitignore
vendored
2
.gitignore
vendored
@ -71,3 +71,5 @@ fabric.properties
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
env.list
|
||||
|
||||
gen
|
20
README.md
20
README.md
@ -19,8 +19,19 @@
|
||||
* inWhiteList("field")
|
||||
* inBlackList("field")
|
||||
* like("field", "regexp_in_java_style"[1])
|
||||
* countryBy("field") - this function can return result "unknown", you must remember it!
|
||||
* amount()
|
||||
* country() - this function can return result "unknown", you must remember it!
|
||||
~~~~
|
||||
|
||||
##### group_field:
|
||||
* email,
|
||||
* ip,
|
||||
* fingerprint,
|
||||
* bin,
|
||||
* shop_ip,
|
||||
* party_id,
|
||||
* card_token
|
||||
|
||||
1. [regexp_in_java_style](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html)
|
||||
##### RESULTS:
|
||||
~~~~
|
||||
@ -54,9 +65,14 @@ rule: unique("email", "ip") < 4
|
||||
~~~~
|
||||
###### Check country by ip:
|
||||
~~~~
|
||||
rule: countryBy("ip") = "RU"
|
||||
rule: country() = "RU"
|
||||
-> notify;
|
||||
~~~~
|
||||
###### Check current amount:
|
||||
~~~~
|
||||
rule: amount() < 100
|
||||
-> accept;
|
||||
~~~~
|
||||
###### Combined check:
|
||||
~~~~
|
||||
rule: 3 > 2 AND 1 > 1
|
||||
|
@ -5,7 +5,7 @@ parse
|
||||
;
|
||||
|
||||
fraud_rule
|
||||
: RULE_BLOCK expression RETURN result SCOL
|
||||
: RULE_BLOCK expression RETURN result (CATCH_ERROR catch_result)? SCOL
|
||||
;
|
||||
|
||||
expression
|
||||
@ -25,7 +25,8 @@ expression
|
||||
| in_white_list #inWhiteListExpression
|
||||
| in_black_list #inBlackListExpression
|
||||
| like #likeFunctionExpression
|
||||
| country_by #countryByFunctionExpression
|
||||
| country #countryFunctionExpression
|
||||
| amount #amountFunctionExpression
|
||||
| IDENTIFIER #identifierExpression
|
||||
| DECIMAL #decimalExpression
|
||||
| STRING #stringExpression
|
||||
@ -43,6 +44,10 @@ bool
|
||||
: TRUE | FALSE
|
||||
;
|
||||
|
||||
amount
|
||||
: 'amount' LPAREN RPAREN
|
||||
;
|
||||
|
||||
count
|
||||
: 'count' LPAREN STRING DELIMETER DECIMAL RPAREN
|
||||
;
|
||||
@ -87,14 +92,18 @@ like
|
||||
: 'like' LPAREN STRING DELIMETER STRING RPAREN
|
||||
;
|
||||
|
||||
country_by
|
||||
: 'countryBy' LPAREN STRING RPAREN
|
||||
country
|
||||
: 'country' LPAREN RPAREN
|
||||
;
|
||||
|
||||
result
|
||||
: 'accept' | '3ds' | 'decline' | 'notify'
|
||||
;
|
||||
|
||||
catch_result
|
||||
: 'accept' | '3ds' | 'decline' | 'notify'
|
||||
;
|
||||
|
||||
string_list
|
||||
: STRING (',' STRING | WS)+
|
||||
;
|
||||
@ -110,12 +119,13 @@ COMMENT
|
||||
;
|
||||
|
||||
RETURN : '->' ;
|
||||
CATCH_ERROR: 'catch:' ;
|
||||
RULE_BLOCK : 'rule:' ;
|
||||
AND : 'AND' ;
|
||||
OR : 'OR' ;
|
||||
NOT : 'NOT';
|
||||
TRUE : 'TRUE' ;
|
||||
FALSE : 'FALSE' ;
|
||||
AND : 'AND' | 'and';
|
||||
OR : 'OR' | 'or' ;
|
||||
NOT : 'NOT' | 'not';
|
||||
TRUE : 'TRUE' | 'true';
|
||||
FALSE : 'FALSE' | 'false';
|
||||
GT : '>' ;
|
||||
GE : '>=' ;
|
||||
LT : '<' ;
|
||||
|
@ -1,11 +1,9 @@
|
||||
package com.rbkmoney.fraudo.resolver;
|
||||
|
||||
import com.rbkmoney.fraudo.constant.CheckedField;
|
||||
|
||||
public interface CountryResolver {
|
||||
|
||||
String UNKNOWN_VALUE = "unknown";
|
||||
|
||||
String resolveCountry(CheckedField checkedField, String value);
|
||||
String resolveCountryByIp(String value);
|
||||
|
||||
}
|
||||
|
@ -19,10 +19,8 @@ public class CustomFuncVisitorImpl extends FraudoBaseVisitor<Object> {
|
||||
private final CountryResolver countryResolver;
|
||||
|
||||
@Override
|
||||
public Object visitCountry_by(FraudoParser.Country_byContext ctx) {
|
||||
String fieldName = TextUtil.safeGetText(ctx.STRING());
|
||||
String fieldValue = FieldResolver.resolveString(fieldName, fraudModel);
|
||||
return countryResolver.resolveCountry(CheckedField.getByValue(fieldName), fieldValue);
|
||||
public Object visitCountry(FraudoParser.CountryContext ctx) {
|
||||
return countryResolver.resolveCountryByIp(fraudModel.getIp());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -53,4 +51,8 @@ public class CustomFuncVisitorImpl extends FraudoBaseVisitor<Object> {
|
||||
CheckedField.getByValue(fieldBy));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitAmount(FraudoParser.AmountContext ctx) {
|
||||
return (double) fraudModel.getAmount();
|
||||
}
|
||||
}
|
||||
|
@ -22,8 +22,15 @@ public class FastFraudVisitorImpl extends FraudoBaseVisitor<Object> {
|
||||
|
||||
@Override
|
||||
public Object visitFraud_rule(com.rbkmoney.fraudo.FraudoParser.Fraud_ruleContext ctx) {
|
||||
try {
|
||||
if (asBoolean(ctx.expression())) {
|
||||
return super.visit(ctx.result());
|
||||
return ResultStatus.getByValue((String) super.visit(ctx.result()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (ctx.catch_result() != null && ctx.catch_result().getText() != null) {
|
||||
return ResultStatus.getByValue(ctx.catch_result().getText());
|
||||
}
|
||||
return ResultStatus.THREE_DS;
|
||||
}
|
||||
return ResultStatus.NORMAL;
|
||||
}
|
||||
@ -32,15 +39,13 @@ public class FastFraudVisitorImpl extends FraudoBaseVisitor<Object> {
|
||||
public Object visitParse(com.rbkmoney.fraudo.FraudoParser.ParseContext ctx) {
|
||||
List<String> notifications = new ArrayList<>();
|
||||
for (com.rbkmoney.fraudo.FraudoParser.Fraud_ruleContext fraud_ruleContext : ctx.fraud_rule()) {
|
||||
if (asBoolean(fraud_ruleContext.expression())) {
|
||||
String result = fraud_ruleContext.result().getText();
|
||||
if (result != null && ResultStatus.NOTIFY.equals(ResultStatus.getByValue(result))) {
|
||||
ResultStatus result = (ResultStatus) visitFraud_rule(fraud_ruleContext);
|
||||
if (result != null && ResultStatus.NOTIFY.equals(result)) {
|
||||
notifications.add(String.valueOf(fraud_ruleContext.getRuleIndex()));
|
||||
} else if (result != null && ResultStatus.getByValue(result) != null) {
|
||||
return new ResultModel(ResultStatus.getByValue(result), notifications);
|
||||
} else {
|
||||
throw new UnknownResultException(result);
|
||||
}
|
||||
} else if (result != null && !ResultStatus.NORMAL.equals(result)) {
|
||||
return new ResultModel(result, notifications);
|
||||
} else if (result == null) {
|
||||
throw new UnknownResultException(fraud_ruleContext.getText());
|
||||
}
|
||||
}
|
||||
return new ResultModel(ResultStatus.NORMAL, notifications);
|
||||
@ -133,8 +138,8 @@ public class FastFraudVisitorImpl extends FraudoBaseVisitor<Object> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCountry_by(FraudoParser.Country_byContext ctx) {
|
||||
return customFuncVisitor.visitCountry_by(ctx);
|
||||
public Object visitCountry(FraudoParser.CountryContext ctx) {
|
||||
return customFuncVisitor.visitCountry(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -162,6 +167,11 @@ public class FastFraudVisitorImpl extends FraudoBaseVisitor<Object> {
|
||||
return listVisitor.visitIn_black_list(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitAmount(FraudoParser.AmountContext ctx) {
|
||||
return customFuncVisitor.visitAmount(ctx);
|
||||
}
|
||||
|
||||
private boolean asBoolean(com.rbkmoney.fraudo.FraudoParser.ExpressionContext ctx) {
|
||||
return (boolean) visit(ctx);
|
||||
}
|
||||
|
@ -49,12 +49,8 @@ public class FraudoTest {
|
||||
@Test
|
||||
public void threeDsTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/three_ds.frd");
|
||||
com.rbkmoney.fraudo.FraudoLexer lexer = new com.rbkmoney.fraudo.FraudoLexer(new ANTLRInputStream(resourceAsStream));
|
||||
com.rbkmoney.fraudo.FraudoParser parser = new com.rbkmoney.fraudo.FraudoParser(new CommonTokenStream(lexer));
|
||||
|
||||
Mockito.when(countAggregator.count(anyObject(), any(), anyLong())).thenReturn(10);
|
||||
ResultModel result = (ResultModel) new FastFraudVisitorFactory().createVisitor(new FraudModel(), countAggregator,
|
||||
sumAggregator, uniqueValueAggregator, countryResolver, blackListFinder, whiteListFinder).visit(parser.parse());
|
||||
ResultModel result = parseAndVisit(resourceAsStream);
|
||||
Assert.assertEquals(ResultStatus.THREE_DS, result.getResultStatus());
|
||||
}
|
||||
|
||||
@ -141,6 +137,25 @@ public class FraudoTest {
|
||||
Assert.assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void amountTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/amount.frd");
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
FraudModel model = new FraudModel();
|
||||
model.setAmount(56L);
|
||||
ResultModel result = invoke(parseContext, model);
|
||||
Assert.assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void catchTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/catch.frd");
|
||||
Mockito.when(uniqueValueAggregator.countUniqueValue(any(), any(), any())).thenThrow(new UnknownResultException("as"));
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void likeTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/like.frd");
|
||||
@ -194,13 +209,13 @@ public class FraudoTest {
|
||||
public void eqCountryTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/eq_country.frd");
|
||||
|
||||
Mockito.when(countryResolver.resolveCountry(any(), anyString())).thenReturn("RU");
|
||||
Mockito.when(countryResolver.resolveCountryByIp( anyString())).thenReturn("RU");
|
||||
|
||||
ResultModel result = parseAndVisit(resourceAsStream);
|
||||
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
Assert.assertEquals(1, result.getNotificationsRule().size());
|
||||
|
||||
Mockito.when(countryResolver.resolveCountry(any(), anyString())).thenReturn("US");
|
||||
Mockito.when(countryResolver.resolveCountryByIp( anyString())).thenReturn("US");
|
||||
resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/eq_country.frd");
|
||||
result = parseAndVisit(resourceAsStream);
|
||||
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
|
2
src/test/resources/rules/amount.frd
Normal file
2
src/test/resources/rules/amount.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: amount() < 100
|
||||
-> accept;
|
3
src/test/resources/rules/catch.frd
Normal file
3
src/test/resources/rules/catch.frd
Normal file
@ -0,0 +1,3 @@
|
||||
rule: unique("email", "ip") < 4
|
||||
-> accept
|
||||
catch: decline;
|
@ -1,2 +1,2 @@
|
||||
rule: countryBy("ip") = "RU"
|
||||
rule: country() = "RU"
|
||||
-> notify;
|
@ -1,3 +1,3 @@
|
||||
rule: (sum("ip", 1444) >= 10500.50 OR sumSuccess("email", 1444) > 500)
|
||||
AND sumError("fingerprint", 1444, "error_code") > 523.12
|
||||
rule: (sum("ip", 1444) >= 10500.50 or sumSuccess("email", 1444) > 500)
|
||||
and sumError("fingerprint", 1444, "error_code") > 523.12
|
||||
-> notify;
|
BIN
syntax.png
BIN
syntax.png
Binary file not shown.
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 17 KiB |
Loading…
Reference in New Issue
Block a user