@infrab4a/connect 5.7.10-alpha.0 → 5.7.10-alpha.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/index.cjs.js
CHANGED
|
@@ -1933,62 +1933,153 @@ class AntifraudBankSlipService {
|
|
|
1933
1933
|
}
|
|
1934
1934
|
}
|
|
1935
1935
|
|
|
1936
|
+
const ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS = 60;
|
|
1937
|
+
/** Defaults personalizáveis via shopConfigs.antifraude; usados só como fallback. */
|
|
1938
|
+
const DEFAULT_ANTIFRAUD_VOLUME_LIMITS = {
|
|
1939
|
+
enabled: true,
|
|
1940
|
+
source: 'fallback',
|
|
1941
|
+
day: {
|
|
1942
|
+
subscriber: { cpf: 4, email: 4, phone: 4, card: 4, zip: 4 },
|
|
1943
|
+
nonSubscriber: { cpf: 2, email: 2, phone: 2, card: 2, zip: 2 },
|
|
1944
|
+
},
|
|
1945
|
+
week: {
|
|
1946
|
+
subscriber: { cpf: 12, email: 12, phone: 12, card: 12, zip: Infinity },
|
|
1947
|
+
nonSubscriber: { cpf: 7, email: 7, phone: 7, card: 7, zip: Infinity },
|
|
1948
|
+
},
|
|
1949
|
+
blockedAttemptsDay: {
|
|
1950
|
+
subscriber: 7,
|
|
1951
|
+
nonSubscriber: 5,
|
|
1952
|
+
},
|
|
1953
|
+
};
|
|
1954
|
+
function isPositiveInteger(value) {
|
|
1955
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 1 && Number.isInteger(value);
|
|
1956
|
+
}
|
|
1957
|
+
function normalizeLimitOrders(raw, allowInfiniteZip) {
|
|
1958
|
+
if (!raw)
|
|
1959
|
+
return null;
|
|
1960
|
+
const zip = allowInfiniteZip && (raw.zip === null || raw.zip === undefined || raw.zip === Infinity) ? Infinity : raw.zip;
|
|
1961
|
+
const normalized = {
|
|
1962
|
+
cpf: raw.cpf,
|
|
1963
|
+
email: raw.email,
|
|
1964
|
+
phone: raw.phone,
|
|
1965
|
+
zip: zip,
|
|
1966
|
+
card: raw.card,
|
|
1967
|
+
};
|
|
1968
|
+
for (const key of ['cpf', 'email', 'phone', 'zip', 'card']) {
|
|
1969
|
+
if (key === 'zip' && normalized.zip === Infinity)
|
|
1970
|
+
continue;
|
|
1971
|
+
if (!isPositiveInteger(normalized[key]))
|
|
1972
|
+
return null;
|
|
1973
|
+
}
|
|
1974
|
+
return normalized;
|
|
1975
|
+
}
|
|
1976
|
+
/** Expõe resolução para testes; config inválida → fallback (comportamento atual). */
|
|
1977
|
+
function resolveAntifraudVolumeLimits(antifraude) {
|
|
1978
|
+
if (!antifraude || typeof antifraude.enabled !== 'boolean') {
|
|
1979
|
+
return {
|
|
1980
|
+
...DEFAULT_ANTIFRAUD_VOLUME_LIMITS,
|
|
1981
|
+
day: {
|
|
1982
|
+
subscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.day.subscriber },
|
|
1983
|
+
nonSubscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.day.nonSubscriber },
|
|
1984
|
+
},
|
|
1985
|
+
week: {
|
|
1986
|
+
subscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.week.subscriber },
|
|
1987
|
+
nonSubscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.week.nonSubscriber },
|
|
1988
|
+
},
|
|
1989
|
+
blockedAttemptsDay: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.blockedAttemptsDay },
|
|
1990
|
+
source: 'fallback',
|
|
1991
|
+
};
|
|
1992
|
+
}
|
|
1993
|
+
const daySubscriber = normalizeLimitOrders(antifraude.day?.subscriber, false);
|
|
1994
|
+
const dayNonSubscriber = normalizeLimitOrders(antifraude.day?.nonSubscriber, false);
|
|
1995
|
+
const weekSubscriber = normalizeLimitOrders(antifraude.week?.subscriber, true);
|
|
1996
|
+
const weekNonSubscriber = normalizeLimitOrders(antifraude.week?.nonSubscriber, true);
|
|
1997
|
+
const blocked = antifraude.blockedAttemptsDay;
|
|
1998
|
+
if (!daySubscriber ||
|
|
1999
|
+
!dayNonSubscriber ||
|
|
2000
|
+
!weekSubscriber ||
|
|
2001
|
+
!weekNonSubscriber ||
|
|
2002
|
+
!blocked ||
|
|
2003
|
+
!isPositiveInteger(blocked.subscriber) ||
|
|
2004
|
+
!isPositiveInteger(blocked.nonSubscriber)) {
|
|
2005
|
+
// Kill-switch explícito prevalece mesmo com payload inválido (senão o fallback religaria o volume).
|
|
2006
|
+
if (antifraude.enabled === false) {
|
|
2007
|
+
const fallback = resolveAntifraudVolumeLimits(null);
|
|
2008
|
+
return { ...fallback, enabled: false, source: 'fallback' };
|
|
2009
|
+
}
|
|
2010
|
+
return resolveAntifraudVolumeLimits(null);
|
|
2011
|
+
}
|
|
2012
|
+
return {
|
|
2013
|
+
enabled: antifraude.enabled,
|
|
2014
|
+
source: 'config',
|
|
2015
|
+
day: { subscriber: daySubscriber, nonSubscriber: dayNonSubscriber },
|
|
2016
|
+
week: { subscriber: weekSubscriber, nonSubscriber: weekNonSubscriber },
|
|
2017
|
+
blockedAttemptsDay: {
|
|
2018
|
+
subscriber: blocked.subscriber,
|
|
2019
|
+
nonSubscriber: blocked.nonSubscriber,
|
|
2020
|
+
},
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
1936
2023
|
class AntifraudCardService {
|
|
1937
|
-
constructor(orderRepository, orderBlockedRepository) {
|
|
2024
|
+
constructor(orderRepository, orderBlockedRepository, shopConfigsRepository) {
|
|
1938
2025
|
this.orderRepository = orderRepository;
|
|
1939
2026
|
this.orderBlockedRepository = orderBlockedRepository;
|
|
1940
|
-
this.
|
|
1941
|
-
this.LIMIT_ORDERS_WEEK = null;
|
|
2027
|
+
this.shopConfigsRepository = shopConfigsRepository;
|
|
1942
2028
|
}
|
|
1943
2029
|
async validate(checkout, card) {
|
|
1944
|
-
|
|
1945
|
-
await this.
|
|
1946
|
-
|
|
2030
|
+
// Limites locais por request — evita race em provider Nest singleton entre awaits.
|
|
2031
|
+
const resolved = await this.loadResolvedLimits();
|
|
2032
|
+
const isSubscriber = !!checkout.user?.isSubscriber;
|
|
2033
|
+
const dayLimits = isSubscriber ? resolved.day.subscriber : resolved.day.nonSubscriber;
|
|
2034
|
+
const weekLimits = isSubscriber ? resolved.week.subscriber : resolved.week.nonSubscriber;
|
|
2035
|
+
const blockedAttemptsDay = isSubscriber
|
|
2036
|
+
? resolved.blockedAttemptsDay.subscriber
|
|
2037
|
+
: resolved.blockedAttemptsDay.nonSubscriber;
|
|
2038
|
+
if (!resolved.enabled) {
|
|
2039
|
+
console.info(JSON.stringify({
|
|
2040
|
+
msg: 'antifraud_card_volume_skipped',
|
|
2041
|
+
source: resolved.source,
|
|
2042
|
+
enabled: false,
|
|
2043
|
+
checkoutId: checkout.id,
|
|
2044
|
+
isSubscriber,
|
|
2045
|
+
}));
|
|
2046
|
+
return true;
|
|
2047
|
+
}
|
|
2048
|
+
console.info(JSON.stringify({
|
|
2049
|
+
msg: 'antifraud_card_volume_limits',
|
|
2050
|
+
source: resolved.source,
|
|
2051
|
+
enabled: true,
|
|
2052
|
+
checkoutId: checkout.id,
|
|
2053
|
+
isSubscriber,
|
|
2054
|
+
blockedAttemptsDay,
|
|
2055
|
+
day: dayLimits,
|
|
2056
|
+
week: weekLimits,
|
|
2057
|
+
}));
|
|
2058
|
+
await this.validateBlockedOrderAttempts(checkout, card, blockedAttemptsDay);
|
|
2059
|
+
await this.validateDayAndWeekOrderLimits(checkout, card, dayLimits, weekLimits);
|
|
1947
2060
|
return true;
|
|
1948
2061
|
}
|
|
1949
|
-
|
|
1950
|
-
this.
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
};
|
|
1966
|
-
this.LIMIT_ORDERS_WEEK = {
|
|
1967
|
-
subscriber: {
|
|
1968
|
-
cpf: 12,
|
|
1969
|
-
email: 12,
|
|
1970
|
-
phone: 12,
|
|
1971
|
-
card: 12,
|
|
1972
|
-
zip: Infinity,
|
|
1973
|
-
},
|
|
1974
|
-
nonSubscriber: {
|
|
1975
|
-
cpf: 7,
|
|
1976
|
-
email: 7,
|
|
1977
|
-
phone: 7,
|
|
1978
|
-
card: 7,
|
|
1979
|
-
zip: Infinity,
|
|
1980
|
-
},
|
|
1981
|
-
};
|
|
1982
|
-
this.LIMIT_BLOCKED_ORDERS_DAY = isSubscriber ? 7 : 5;
|
|
1983
|
-
}
|
|
1984
|
-
getLimitsByUserType(type, isSubscriber) {
|
|
1985
|
-
const limits = type === 'day' ? this.LIMIT_ORDERS_DAY : this.LIMIT_ORDERS_WEEK;
|
|
1986
|
-
return isSubscriber ? limits['subscriber'] : limits['nonSubscriber'];
|
|
2062
|
+
async loadResolvedLimits() {
|
|
2063
|
+
if (!this.shopConfigsRepository) {
|
|
2064
|
+
return resolveAntifraudVolumeLimits(null);
|
|
2065
|
+
}
|
|
2066
|
+
try {
|
|
2067
|
+
const result = await this.shopConfigsRepository.find({}, { cache: { enabled: true, ttl: ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS } });
|
|
2068
|
+
return resolveAntifraudVolumeLimits(result?.data?.at(0)?.antifraude);
|
|
2069
|
+
}
|
|
2070
|
+
catch (error) {
|
|
2071
|
+
console.warn(JSON.stringify({
|
|
2072
|
+
msg: 'antifraud_card_volume_config_load_failed',
|
|
2073
|
+
source: 'fallback',
|
|
2074
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2075
|
+
}));
|
|
2076
|
+
return resolveAntifraudVolumeLimits(null);
|
|
2077
|
+
}
|
|
1987
2078
|
}
|
|
1988
|
-
async validateBlockedOrderAttempts(checkout, card) {
|
|
1989
|
-
const isValid = await this.verifyBlockedOrderAttempts(checkout, card);
|
|
2079
|
+
async validateBlockedOrderAttempts(checkout, card, blockedAttemptsDay) {
|
|
2080
|
+
const isValid = await this.verifyBlockedOrderAttempts(checkout, card, blockedAttemptsDay);
|
|
1990
2081
|
if (!isValid) {
|
|
1991
|
-
throw new FraudValidationError(`Cliente com mais de ${
|
|
2082
|
+
throw new FraudValidationError(`Cliente com mais de ${blockedAttemptsDay} compras negadas/bloqueadas no dia`, exports.ErrorsCode.fraudPreventionInternal, {
|
|
1992
2083
|
checkoutId: checkout.id,
|
|
1993
2084
|
userEmail: checkout.user.email,
|
|
1994
2085
|
info: {
|
|
@@ -1999,8 +2090,8 @@ class AntifraudCardService {
|
|
|
1999
2090
|
});
|
|
2000
2091
|
}
|
|
2001
2092
|
}
|
|
2002
|
-
async validateDayAndWeekOrderLimits(checkout, card) {
|
|
2003
|
-
const isValid = await this.verifyDayAndWeekOrders(checkout, card);
|
|
2093
|
+
async validateDayAndWeekOrderLimits(checkout, card, dayLimits, weekLimits) {
|
|
2094
|
+
const isValid = await this.verifyDayAndWeekOrders(checkout, card, dayLimits, weekLimits);
|
|
2004
2095
|
if (!isValid) {
|
|
2005
2096
|
throw new FraudValidationError('Cliente tentando comprar mais do que o permitido no dia/semana', exports.ErrorsCode.fraudPreventionInternal, {
|
|
2006
2097
|
checkoutId: checkout.id,
|
|
@@ -2013,15 +2104,15 @@ class AntifraudCardService {
|
|
|
2013
2104
|
});
|
|
2014
2105
|
}
|
|
2015
2106
|
}
|
|
2016
|
-
async verifyBlockedOrderAttempts(checkout, card) {
|
|
2107
|
+
async verifyBlockedOrderAttempts(checkout, card, blockedAttemptsDay) {
|
|
2017
2108
|
const dateRange = this.getTodayDateRange();
|
|
2018
2109
|
const blockedOrders = await this.getBlockedOrdersByMultipleCriteria(checkout, dateRange);
|
|
2019
2110
|
const totalBlockedAttempts = this.calculateUniqueBlockedAttempts(blockedOrders, checkout);
|
|
2020
|
-
if (totalBlockedAttempts >=
|
|
2111
|
+
if (totalBlockedAttempts >= blockedAttemptsDay) {
|
|
2021
2112
|
await this.createBlockedOrderRecord({
|
|
2022
2113
|
checkout,
|
|
2023
2114
|
card,
|
|
2024
|
-
reason: `More than ${
|
|
2115
|
+
reason: `More than ${blockedAttemptsDay} attempts have failed`,
|
|
2025
2116
|
key: 'Failed attempts',
|
|
2026
2117
|
period: 'day',
|
|
2027
2118
|
});
|
|
@@ -2123,12 +2214,12 @@ class AntifraudCardService {
|
|
|
2123
2214
|
card,
|
|
2124
2215
|
});
|
|
2125
2216
|
}
|
|
2126
|
-
async verifyDayAndWeekOrders(checkout, card) {
|
|
2217
|
+
async verifyDayAndWeekOrders(checkout, card, dayLimits, weekLimits) {
|
|
2127
2218
|
const validationParams = this.buildValidationParams(checkout, card);
|
|
2128
|
-
const isDayLimitValid = await this.validateDayOrderLimits(checkout, validationParams);
|
|
2219
|
+
const isDayLimitValid = await this.validateDayOrderLimits(checkout, validationParams, dayLimits);
|
|
2129
2220
|
if (!isDayLimitValid)
|
|
2130
2221
|
return false;
|
|
2131
|
-
const isWeekLimitValid = await this.validateWeekOrderLimits(checkout, validationParams);
|
|
2222
|
+
const isWeekLimitValid = await this.validateWeekOrderLimits(checkout, validationParams, weekLimits);
|
|
2132
2223
|
return isWeekLimitValid;
|
|
2133
2224
|
}
|
|
2134
2225
|
buildValidationParams(checkout, card) {
|
|
@@ -2140,9 +2231,8 @@ class AntifraudCardService {
|
|
|
2140
2231
|
card,
|
|
2141
2232
|
};
|
|
2142
2233
|
}
|
|
2143
|
-
async validateDayOrderLimits(checkout, params) {
|
|
2234
|
+
async validateDayOrderLimits(checkout, params, limits) {
|
|
2144
2235
|
const ordersPerDay = await this.validateOrdersByRange(params, this.getDateRange('day'));
|
|
2145
|
-
const limits = this.getLimitsByUserType('day', checkout.user.isSubscriber);
|
|
2146
2236
|
return this.checkOrderLimitsAndBlock({
|
|
2147
2237
|
checkout,
|
|
2148
2238
|
orderCounts: ordersPerDay,
|
|
@@ -2150,9 +2240,8 @@ class AntifraudCardService {
|
|
|
2150
2240
|
period: 'day',
|
|
2151
2241
|
});
|
|
2152
2242
|
}
|
|
2153
|
-
async validateWeekOrderLimits(checkout, params) {
|
|
2243
|
+
async validateWeekOrderLimits(checkout, params, limits) {
|
|
2154
2244
|
const ordersPerWeek = await this.validateOrdersByRange(params, this.getDateRange('week'));
|
|
2155
|
-
const limits = this.getLimitsByUserType('week', checkout.user.isSubscriber);
|
|
2156
2245
|
return this.checkOrderLimitsAndBlock({
|
|
2157
2246
|
checkout,
|
|
2158
2247
|
orderCounts: ordersPerWeek,
|
|
@@ -11762,6 +11851,7 @@ exports.ConnectDocumentService = ConnectDocumentService;
|
|
|
11762
11851
|
exports.ConnectFirestoreService = ConnectFirestoreService;
|
|
11763
11852
|
exports.Coupon = Coupon;
|
|
11764
11853
|
exports.CouponFirestoreRepository = CouponFirestoreRepository;
|
|
11854
|
+
exports.DEFAULT_ANTIFRAUD_VOLUME_LIMITS = DEFAULT_ANTIFRAUD_VOLUME_LIMITS;
|
|
11765
11855
|
exports.Debug = Debug;
|
|
11766
11856
|
exports.DebugDecoratorHelper = DebugDecoratorHelper;
|
|
11767
11857
|
exports.DebugHelper = DebugHelper;
|
|
@@ -11902,6 +11992,7 @@ exports.isDebuggable = isDebuggable;
|
|
|
11902
11992
|
exports.isUUID = isUUID;
|
|
11903
11993
|
exports.parseDateTime = parseDateTime;
|
|
11904
11994
|
exports.registerClass = registerClass;
|
|
11995
|
+
exports.resolveAntifraudVolumeLimits = resolveAntifraudVolumeLimits;
|
|
11905
11996
|
exports.resolveCacheConfig = resolveCacheConfig;
|
|
11906
11997
|
exports.resolveClass = resolveClass;
|
|
11907
11998
|
exports.serialize = serialize;
|
package/index.esm.js
CHANGED
|
@@ -1927,62 +1927,153 @@ class AntifraudBankSlipService {
|
|
|
1927
1927
|
}
|
|
1928
1928
|
}
|
|
1929
1929
|
|
|
1930
|
+
const ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS = 60;
|
|
1931
|
+
/** Defaults personalizáveis via shopConfigs.antifraude; usados só como fallback. */
|
|
1932
|
+
const DEFAULT_ANTIFRAUD_VOLUME_LIMITS = {
|
|
1933
|
+
enabled: true,
|
|
1934
|
+
source: 'fallback',
|
|
1935
|
+
day: {
|
|
1936
|
+
subscriber: { cpf: 4, email: 4, phone: 4, card: 4, zip: 4 },
|
|
1937
|
+
nonSubscriber: { cpf: 2, email: 2, phone: 2, card: 2, zip: 2 },
|
|
1938
|
+
},
|
|
1939
|
+
week: {
|
|
1940
|
+
subscriber: { cpf: 12, email: 12, phone: 12, card: 12, zip: Infinity },
|
|
1941
|
+
nonSubscriber: { cpf: 7, email: 7, phone: 7, card: 7, zip: Infinity },
|
|
1942
|
+
},
|
|
1943
|
+
blockedAttemptsDay: {
|
|
1944
|
+
subscriber: 7,
|
|
1945
|
+
nonSubscriber: 5,
|
|
1946
|
+
},
|
|
1947
|
+
};
|
|
1948
|
+
function isPositiveInteger(value) {
|
|
1949
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 1 && Number.isInteger(value);
|
|
1950
|
+
}
|
|
1951
|
+
function normalizeLimitOrders(raw, allowInfiniteZip) {
|
|
1952
|
+
if (!raw)
|
|
1953
|
+
return null;
|
|
1954
|
+
const zip = allowInfiniteZip && (raw.zip === null || raw.zip === undefined || raw.zip === Infinity) ? Infinity : raw.zip;
|
|
1955
|
+
const normalized = {
|
|
1956
|
+
cpf: raw.cpf,
|
|
1957
|
+
email: raw.email,
|
|
1958
|
+
phone: raw.phone,
|
|
1959
|
+
zip: zip,
|
|
1960
|
+
card: raw.card,
|
|
1961
|
+
};
|
|
1962
|
+
for (const key of ['cpf', 'email', 'phone', 'zip', 'card']) {
|
|
1963
|
+
if (key === 'zip' && normalized.zip === Infinity)
|
|
1964
|
+
continue;
|
|
1965
|
+
if (!isPositiveInteger(normalized[key]))
|
|
1966
|
+
return null;
|
|
1967
|
+
}
|
|
1968
|
+
return normalized;
|
|
1969
|
+
}
|
|
1970
|
+
/** Expõe resolução para testes; config inválida → fallback (comportamento atual). */
|
|
1971
|
+
function resolveAntifraudVolumeLimits(antifraude) {
|
|
1972
|
+
if (!antifraude || typeof antifraude.enabled !== 'boolean') {
|
|
1973
|
+
return {
|
|
1974
|
+
...DEFAULT_ANTIFRAUD_VOLUME_LIMITS,
|
|
1975
|
+
day: {
|
|
1976
|
+
subscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.day.subscriber },
|
|
1977
|
+
nonSubscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.day.nonSubscriber },
|
|
1978
|
+
},
|
|
1979
|
+
week: {
|
|
1980
|
+
subscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.week.subscriber },
|
|
1981
|
+
nonSubscriber: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.week.nonSubscriber },
|
|
1982
|
+
},
|
|
1983
|
+
blockedAttemptsDay: { ...DEFAULT_ANTIFRAUD_VOLUME_LIMITS.blockedAttemptsDay },
|
|
1984
|
+
source: 'fallback',
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
const daySubscriber = normalizeLimitOrders(antifraude.day?.subscriber, false);
|
|
1988
|
+
const dayNonSubscriber = normalizeLimitOrders(antifraude.day?.nonSubscriber, false);
|
|
1989
|
+
const weekSubscriber = normalizeLimitOrders(antifraude.week?.subscriber, true);
|
|
1990
|
+
const weekNonSubscriber = normalizeLimitOrders(antifraude.week?.nonSubscriber, true);
|
|
1991
|
+
const blocked = antifraude.blockedAttemptsDay;
|
|
1992
|
+
if (!daySubscriber ||
|
|
1993
|
+
!dayNonSubscriber ||
|
|
1994
|
+
!weekSubscriber ||
|
|
1995
|
+
!weekNonSubscriber ||
|
|
1996
|
+
!blocked ||
|
|
1997
|
+
!isPositiveInteger(blocked.subscriber) ||
|
|
1998
|
+
!isPositiveInteger(blocked.nonSubscriber)) {
|
|
1999
|
+
// Kill-switch explícito prevalece mesmo com payload inválido (senão o fallback religaria o volume).
|
|
2000
|
+
if (antifraude.enabled === false) {
|
|
2001
|
+
const fallback = resolveAntifraudVolumeLimits(null);
|
|
2002
|
+
return { ...fallback, enabled: false, source: 'fallback' };
|
|
2003
|
+
}
|
|
2004
|
+
return resolveAntifraudVolumeLimits(null);
|
|
2005
|
+
}
|
|
2006
|
+
return {
|
|
2007
|
+
enabled: antifraude.enabled,
|
|
2008
|
+
source: 'config',
|
|
2009
|
+
day: { subscriber: daySubscriber, nonSubscriber: dayNonSubscriber },
|
|
2010
|
+
week: { subscriber: weekSubscriber, nonSubscriber: weekNonSubscriber },
|
|
2011
|
+
blockedAttemptsDay: {
|
|
2012
|
+
subscriber: blocked.subscriber,
|
|
2013
|
+
nonSubscriber: blocked.nonSubscriber,
|
|
2014
|
+
},
|
|
2015
|
+
};
|
|
2016
|
+
}
|
|
1930
2017
|
class AntifraudCardService {
|
|
1931
|
-
constructor(orderRepository, orderBlockedRepository) {
|
|
2018
|
+
constructor(orderRepository, orderBlockedRepository, shopConfigsRepository) {
|
|
1932
2019
|
this.orderRepository = orderRepository;
|
|
1933
2020
|
this.orderBlockedRepository = orderBlockedRepository;
|
|
1934
|
-
this.
|
|
1935
|
-
this.LIMIT_ORDERS_WEEK = null;
|
|
2021
|
+
this.shopConfigsRepository = shopConfigsRepository;
|
|
1936
2022
|
}
|
|
1937
2023
|
async validate(checkout, card) {
|
|
1938
|
-
|
|
1939
|
-
await this.
|
|
1940
|
-
|
|
2024
|
+
// Limites locais por request — evita race em provider Nest singleton entre awaits.
|
|
2025
|
+
const resolved = await this.loadResolvedLimits();
|
|
2026
|
+
const isSubscriber = !!checkout.user?.isSubscriber;
|
|
2027
|
+
const dayLimits = isSubscriber ? resolved.day.subscriber : resolved.day.nonSubscriber;
|
|
2028
|
+
const weekLimits = isSubscriber ? resolved.week.subscriber : resolved.week.nonSubscriber;
|
|
2029
|
+
const blockedAttemptsDay = isSubscriber
|
|
2030
|
+
? resolved.blockedAttemptsDay.subscriber
|
|
2031
|
+
: resolved.blockedAttemptsDay.nonSubscriber;
|
|
2032
|
+
if (!resolved.enabled) {
|
|
2033
|
+
console.info(JSON.stringify({
|
|
2034
|
+
msg: 'antifraud_card_volume_skipped',
|
|
2035
|
+
source: resolved.source,
|
|
2036
|
+
enabled: false,
|
|
2037
|
+
checkoutId: checkout.id,
|
|
2038
|
+
isSubscriber,
|
|
2039
|
+
}));
|
|
2040
|
+
return true;
|
|
2041
|
+
}
|
|
2042
|
+
console.info(JSON.stringify({
|
|
2043
|
+
msg: 'antifraud_card_volume_limits',
|
|
2044
|
+
source: resolved.source,
|
|
2045
|
+
enabled: true,
|
|
2046
|
+
checkoutId: checkout.id,
|
|
2047
|
+
isSubscriber,
|
|
2048
|
+
blockedAttemptsDay,
|
|
2049
|
+
day: dayLimits,
|
|
2050
|
+
week: weekLimits,
|
|
2051
|
+
}));
|
|
2052
|
+
await this.validateBlockedOrderAttempts(checkout, card, blockedAttemptsDay);
|
|
2053
|
+
await this.validateDayAndWeekOrderLimits(checkout, card, dayLimits, weekLimits);
|
|
1941
2054
|
return true;
|
|
1942
2055
|
}
|
|
1943
|
-
|
|
1944
|
-
this.
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
};
|
|
1960
|
-
this.LIMIT_ORDERS_WEEK = {
|
|
1961
|
-
subscriber: {
|
|
1962
|
-
cpf: 12,
|
|
1963
|
-
email: 12,
|
|
1964
|
-
phone: 12,
|
|
1965
|
-
card: 12,
|
|
1966
|
-
zip: Infinity,
|
|
1967
|
-
},
|
|
1968
|
-
nonSubscriber: {
|
|
1969
|
-
cpf: 7,
|
|
1970
|
-
email: 7,
|
|
1971
|
-
phone: 7,
|
|
1972
|
-
card: 7,
|
|
1973
|
-
zip: Infinity,
|
|
1974
|
-
},
|
|
1975
|
-
};
|
|
1976
|
-
this.LIMIT_BLOCKED_ORDERS_DAY = isSubscriber ? 7 : 5;
|
|
1977
|
-
}
|
|
1978
|
-
getLimitsByUserType(type, isSubscriber) {
|
|
1979
|
-
const limits = type === 'day' ? this.LIMIT_ORDERS_DAY : this.LIMIT_ORDERS_WEEK;
|
|
1980
|
-
return isSubscriber ? limits['subscriber'] : limits['nonSubscriber'];
|
|
2056
|
+
async loadResolvedLimits() {
|
|
2057
|
+
if (!this.shopConfigsRepository) {
|
|
2058
|
+
return resolveAntifraudVolumeLimits(null);
|
|
2059
|
+
}
|
|
2060
|
+
try {
|
|
2061
|
+
const result = await this.shopConfigsRepository.find({}, { cache: { enabled: true, ttl: ANTIFRAUD_CONFIG_CACHE_TTL_SECONDS } });
|
|
2062
|
+
return resolveAntifraudVolumeLimits(result?.data?.at(0)?.antifraude);
|
|
2063
|
+
}
|
|
2064
|
+
catch (error) {
|
|
2065
|
+
console.warn(JSON.stringify({
|
|
2066
|
+
msg: 'antifraud_card_volume_config_load_failed',
|
|
2067
|
+
source: 'fallback',
|
|
2068
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2069
|
+
}));
|
|
2070
|
+
return resolveAntifraudVolumeLimits(null);
|
|
2071
|
+
}
|
|
1981
2072
|
}
|
|
1982
|
-
async validateBlockedOrderAttempts(checkout, card) {
|
|
1983
|
-
const isValid = await this.verifyBlockedOrderAttempts(checkout, card);
|
|
2073
|
+
async validateBlockedOrderAttempts(checkout, card, blockedAttemptsDay) {
|
|
2074
|
+
const isValid = await this.verifyBlockedOrderAttempts(checkout, card, blockedAttemptsDay);
|
|
1984
2075
|
if (!isValid) {
|
|
1985
|
-
throw new FraudValidationError(`Cliente com mais de ${
|
|
2076
|
+
throw new FraudValidationError(`Cliente com mais de ${blockedAttemptsDay} compras negadas/bloqueadas no dia`, ErrorsCode.fraudPreventionInternal, {
|
|
1986
2077
|
checkoutId: checkout.id,
|
|
1987
2078
|
userEmail: checkout.user.email,
|
|
1988
2079
|
info: {
|
|
@@ -1993,8 +2084,8 @@ class AntifraudCardService {
|
|
|
1993
2084
|
});
|
|
1994
2085
|
}
|
|
1995
2086
|
}
|
|
1996
|
-
async validateDayAndWeekOrderLimits(checkout, card) {
|
|
1997
|
-
const isValid = await this.verifyDayAndWeekOrders(checkout, card);
|
|
2087
|
+
async validateDayAndWeekOrderLimits(checkout, card, dayLimits, weekLimits) {
|
|
2088
|
+
const isValid = await this.verifyDayAndWeekOrders(checkout, card, dayLimits, weekLimits);
|
|
1998
2089
|
if (!isValid) {
|
|
1999
2090
|
throw new FraudValidationError('Cliente tentando comprar mais do que o permitido no dia/semana', ErrorsCode.fraudPreventionInternal, {
|
|
2000
2091
|
checkoutId: checkout.id,
|
|
@@ -2007,15 +2098,15 @@ class AntifraudCardService {
|
|
|
2007
2098
|
});
|
|
2008
2099
|
}
|
|
2009
2100
|
}
|
|
2010
|
-
async verifyBlockedOrderAttempts(checkout, card) {
|
|
2101
|
+
async verifyBlockedOrderAttempts(checkout, card, blockedAttemptsDay) {
|
|
2011
2102
|
const dateRange = this.getTodayDateRange();
|
|
2012
2103
|
const blockedOrders = await this.getBlockedOrdersByMultipleCriteria(checkout, dateRange);
|
|
2013
2104
|
const totalBlockedAttempts = this.calculateUniqueBlockedAttempts(blockedOrders, checkout);
|
|
2014
|
-
if (totalBlockedAttempts >=
|
|
2105
|
+
if (totalBlockedAttempts >= blockedAttemptsDay) {
|
|
2015
2106
|
await this.createBlockedOrderRecord({
|
|
2016
2107
|
checkout,
|
|
2017
2108
|
card,
|
|
2018
|
-
reason: `More than ${
|
|
2109
|
+
reason: `More than ${blockedAttemptsDay} attempts have failed`,
|
|
2019
2110
|
key: 'Failed attempts',
|
|
2020
2111
|
period: 'day',
|
|
2021
2112
|
});
|
|
@@ -2117,12 +2208,12 @@ class AntifraudCardService {
|
|
|
2117
2208
|
card,
|
|
2118
2209
|
});
|
|
2119
2210
|
}
|
|
2120
|
-
async verifyDayAndWeekOrders(checkout, card) {
|
|
2211
|
+
async verifyDayAndWeekOrders(checkout, card, dayLimits, weekLimits) {
|
|
2121
2212
|
const validationParams = this.buildValidationParams(checkout, card);
|
|
2122
|
-
const isDayLimitValid = await this.validateDayOrderLimits(checkout, validationParams);
|
|
2213
|
+
const isDayLimitValid = await this.validateDayOrderLimits(checkout, validationParams, dayLimits);
|
|
2123
2214
|
if (!isDayLimitValid)
|
|
2124
2215
|
return false;
|
|
2125
|
-
const isWeekLimitValid = await this.validateWeekOrderLimits(checkout, validationParams);
|
|
2216
|
+
const isWeekLimitValid = await this.validateWeekOrderLimits(checkout, validationParams, weekLimits);
|
|
2126
2217
|
return isWeekLimitValid;
|
|
2127
2218
|
}
|
|
2128
2219
|
buildValidationParams(checkout, card) {
|
|
@@ -2134,9 +2225,8 @@ class AntifraudCardService {
|
|
|
2134
2225
|
card,
|
|
2135
2226
|
};
|
|
2136
2227
|
}
|
|
2137
|
-
async validateDayOrderLimits(checkout, params) {
|
|
2228
|
+
async validateDayOrderLimits(checkout, params, limits) {
|
|
2138
2229
|
const ordersPerDay = await this.validateOrdersByRange(params, this.getDateRange('day'));
|
|
2139
|
-
const limits = this.getLimitsByUserType('day', checkout.user.isSubscriber);
|
|
2140
2230
|
return this.checkOrderLimitsAndBlock({
|
|
2141
2231
|
checkout,
|
|
2142
2232
|
orderCounts: ordersPerDay,
|
|
@@ -2144,9 +2234,8 @@ class AntifraudCardService {
|
|
|
2144
2234
|
period: 'day',
|
|
2145
2235
|
});
|
|
2146
2236
|
}
|
|
2147
|
-
async validateWeekOrderLimits(checkout, params) {
|
|
2237
|
+
async validateWeekOrderLimits(checkout, params, limits) {
|
|
2148
2238
|
const ordersPerWeek = await this.validateOrdersByRange(params, this.getDateRange('week'));
|
|
2149
|
-
const limits = this.getLimitsByUserType('week', checkout.user.isSubscriber);
|
|
2150
2239
|
return this.checkOrderLimitsAndBlock({
|
|
2151
2240
|
checkout,
|
|
2152
2241
|
orderCounts: ordersPerWeek,
|
|
@@ -11581,4 +11670,4 @@ class ProductsVertexSearch {
|
|
|
11581
11670
|
}
|
|
11582
11671
|
}
|
|
11583
11672
|
|
|
11584
|
-
export { AccessoryImportances, Address, AdyenCardAxiosAdapter, AdyenPaymentMethodFactory, AntifraudBankSlipService, AntifraudCardService, AntifraudGlampointsService, AntifraudPixService, AntifraudProviderFactory, AntifraudProviders, Area, Authentication, AuthenticationFirebaseAuthService, AxiosAdapter, Base, BaseModel, BeardProblems, BeardSizes, BeautyProductImportances, BeautyProfile, BeautyQuestionsHelper, BillingStatus, BodyProblems, BodyShapes, BodyTattoos, BrandCategory, BrandCategoryFirestoreRepository, BrandEquityOptions, BusinessError, BusinessUnitEnum, Buy2Win, Buy2WinFirestoreRepository, Campaign, CampaignBanner, CampaignDashboard, CampaignDashboardFirestoreRepository, CampaignHashtag, CampaignHashtagFirestoreRepository, Category, CategoryCollectionChildren, CategoryCollectionChildrenHasuraGraphQLRepository, CategoryFilter, CategoryFilterHasuraGraphQLRepository, CategoryFirestoreRepository, CategoryHasuraGraphQL, CategoryHasuraGraphQLRepository, CategoryProduct, CategoryProductHasuraGraphQLRepository, Checkout, CheckoutFirestoreRepository, CheckoutSubscription, CheckoutSubscriptionFirestoreRepository, CheckoutTypes, ClassNameHelper, ConnectBaseDocumentSnapshot, ConnectCollectionService, ConnectDocumentService, ConnectFirestoreService, Coupon, CouponCategories, CouponCategory, CouponChannels, CouponFirestoreRepository, CouponOldCategories, CouponSubtypes, CouponTypes, Debug, DebugDecoratorHelper, DebugHelper, DebugNamespaces, DuplicatedResultsError, Edition, EditionStatus, ErrorsCode, Exclusivities, FaceSkinOilinesses, FaceSkinProblems, FaceSkinTones, FamilyIncomes, Filter, FilterHasuraGraphQLRepository, FilterOption, FilterOptionHasuraGraphQLRepository, FilterType, FirebaseFileUploaderService, FragranceImportances, FraudValidationError, GenderDestination, GlampointsPaymentMethodFactory, GlampointsPaymentService, Group, GroupFirestoreRepository, HairColors, HairProblems, HairStrands, HairTypes, Home, HomeFirestoreRepository, InvalidArgumentError, InvalidCheckoutError, KitProduct, KitProductHasuraGraphQL, Lead, LeadFirestoreRepository, LegacyOrderFirestoreRepository, LineItem, Log, LogDocument, LogFirestoreRepository, Logger, MercadoPagoBankSlipAxiosAdapter, MercadoPagoCardAxiosAdapter, MercadoPagoErrorHelper, MercadoPagoPaymentMethodFactory, MercadoPagoPixAxiosAdapter, MercadoPagoRequestHelper, MercadoPagoResponseHelper, MercadoPagoStatusDetailEnum, MercadoPagoStatusEnum, NotFoundError, ObsEmitter, OfficePosition, Order, OrderBlocked, OrderBlockedFirestoreRepository, OrderBlockedType, OrderFirestoreRepository, OrderPaymentStatus, OrderStatus, PagarMeV5OrderStatus, PagarMeV5PaymentStatus, PagarmeBankSlipAxiosAdapter, PagarmeCardAxiosAdapter, PagarmePaymentMethodFactory, PagarmePaymentStatus, PagarmePixAxiosAdapter, PagarmeV5BankSlipAxiosAdapter, PagarmeV5BaseAxiosAdapter, PagarmeV5CardAxiosAdapter, PagarmeV5PixAxiosAdapter, Payment, PaymentError, PaymentFirestoreRepository, PaymentMethods, PaymentProviderFactory, PaymentProviders, PaymentTransaction, PaymentType, PersonTypes, Plans, Product, ProductCatalogHasuraGraphQL, ProductCatalogHasuraGraphQLRepository, ProductErrors, ProductErrorsHasuraGraphQL, ProductErrorsHasuraGraphQLRepository, ProductFirestoreRepository, ProductGroup, ProductGroupHasuraGraphQLRepository, ProductHasuraGraphQL, ProductHasuraGraphQLRepository, ProductLabelEnum, ProductPriceLog, ProductPriceLogHasuraGraphQLRepository, ProductReview, ProductReviewHasuraGraphQLRepository, ProductSpents, ProductStockEntry, ProductStockEntryHasuraGraphQL, ProductStockEntryHasuraGraphQLRepository, ProductStockNotification, ProductStockNotificationHasuraGraphQLRepository, ProductVariantFirestoreRepository, ProductsIndex, ProductsVertexSearch, QuestionsFilters, RecoveryPassword, ReflectHelper, Register, RegisterFirebaseAuthService, RequiredArgumentError, RestCacheAdapter, RoundProductPricesHelper, Sequence, SequenceFirestoreRepository, ShippingMethod, ShopConfigs, ShopConfigsFirestoreRepository, ShopMenu, ShopMenuFirestoreRepository, ShopPageName, ShopSettings, ShopSettingsFirestoreRepository, ShoppingRecurrence, ShoppingRecurrenceCycle, ShoppingRecurrenceEdition, ShoppingRecurrenceEditionFirestoreRepository, ShoppingRecurrenceEditionStatus, ShoppingRecurrenceErrorLog, ShoppingRecurrenceErrorLogFirestoreRepository, ShoppingRecurrenceFirestoreRepository, ShoppingRecurrenceStatus, Shops, SignInMethods, SignOut, Status, StockLimitError, StockOutError, Subscription, SubscriptionEditionFirestoreRepository, SubscriptionFirestoreRepository, SubscriptionMaterialization, SubscriptionMaterializationFirestoreRepository, SubscriptionPayment, SubscriptionPaymentFirestoreRepository, SubscriptionPlan, SubscriptionPlanFirestoreRepository, SubscriptionProductFirestoreRepository, SubscriptionSummary, SubscriptionSummaryFirestoreRepository, Trace, TransactionPaymentMethods, UnauthorizedError, UpdateOptionActions, UpdateUserImage, User, UserAddress, UserAddressFirestoreRepository, UserAlreadyRegisteredError, UserBeautyProfileFirestoreRepository, UserFirestoreRepository, UserPaymentMethod, UserPaymentMethodFirestoreRepository, UserType, Variant, VariantHasuraGraphQL, VariantHasuraGraphQLRepository, VertexAxiosAdapter, WeakPasswordError, Where, Wishlist, WishlistHasuraGraphQLRepository, WishlistLogType, deserialize, getClass, is, isDebuggable, isUUID, parseDateTime, registerClass, resolveCacheConfig, resolveClass, serialize, toCents, withCreateFirestore, withCreateHasuraGraphQL, withCrudFirestore, withCrudHasuraGraphQL, withDeleteFirestore, withDeleteHasuraGraphQL, withFindFirestore, withFindHasuraGraphQL, withFirestore, withGetFirestore, withGetHasuraGraphQL, withHasuraGraphQL, withHelpers, withSubCollection, withUpdateFirestore, withUpdateHasuraGraphQL };
|
|
11673
|
+
export { AccessoryImportances, Address, AdyenCardAxiosAdapter, AdyenPaymentMethodFactory, AntifraudBankSlipService, AntifraudCardService, AntifraudGlampointsService, AntifraudPixService, AntifraudProviderFactory, AntifraudProviders, Area, Authentication, AuthenticationFirebaseAuthService, AxiosAdapter, Base, BaseModel, BeardProblems, BeardSizes, BeautyProductImportances, BeautyProfile, BeautyQuestionsHelper, BillingStatus, BodyProblems, BodyShapes, BodyTattoos, BrandCategory, BrandCategoryFirestoreRepository, BrandEquityOptions, BusinessError, BusinessUnitEnum, Buy2Win, Buy2WinFirestoreRepository, Campaign, CampaignBanner, CampaignDashboard, CampaignDashboardFirestoreRepository, CampaignHashtag, CampaignHashtagFirestoreRepository, Category, CategoryCollectionChildren, CategoryCollectionChildrenHasuraGraphQLRepository, CategoryFilter, CategoryFilterHasuraGraphQLRepository, CategoryFirestoreRepository, CategoryHasuraGraphQL, CategoryHasuraGraphQLRepository, CategoryProduct, CategoryProductHasuraGraphQLRepository, Checkout, CheckoutFirestoreRepository, CheckoutSubscription, CheckoutSubscriptionFirestoreRepository, CheckoutTypes, ClassNameHelper, ConnectBaseDocumentSnapshot, ConnectCollectionService, ConnectDocumentService, ConnectFirestoreService, Coupon, CouponCategories, CouponCategory, CouponChannels, CouponFirestoreRepository, CouponOldCategories, CouponSubtypes, CouponTypes, DEFAULT_ANTIFRAUD_VOLUME_LIMITS, Debug, DebugDecoratorHelper, DebugHelper, DebugNamespaces, DuplicatedResultsError, Edition, EditionStatus, ErrorsCode, Exclusivities, FaceSkinOilinesses, FaceSkinProblems, FaceSkinTones, FamilyIncomes, Filter, FilterHasuraGraphQLRepository, FilterOption, FilterOptionHasuraGraphQLRepository, FilterType, FirebaseFileUploaderService, FragranceImportances, FraudValidationError, GenderDestination, GlampointsPaymentMethodFactory, GlampointsPaymentService, Group, GroupFirestoreRepository, HairColors, HairProblems, HairStrands, HairTypes, Home, HomeFirestoreRepository, InvalidArgumentError, InvalidCheckoutError, KitProduct, KitProductHasuraGraphQL, Lead, LeadFirestoreRepository, LegacyOrderFirestoreRepository, LineItem, Log, LogDocument, LogFirestoreRepository, Logger, MercadoPagoBankSlipAxiosAdapter, MercadoPagoCardAxiosAdapter, MercadoPagoErrorHelper, MercadoPagoPaymentMethodFactory, MercadoPagoPixAxiosAdapter, MercadoPagoRequestHelper, MercadoPagoResponseHelper, MercadoPagoStatusDetailEnum, MercadoPagoStatusEnum, NotFoundError, ObsEmitter, OfficePosition, Order, OrderBlocked, OrderBlockedFirestoreRepository, OrderBlockedType, OrderFirestoreRepository, OrderPaymentStatus, OrderStatus, PagarMeV5OrderStatus, PagarMeV5PaymentStatus, PagarmeBankSlipAxiosAdapter, PagarmeCardAxiosAdapter, PagarmePaymentMethodFactory, PagarmePaymentStatus, PagarmePixAxiosAdapter, PagarmeV5BankSlipAxiosAdapter, PagarmeV5BaseAxiosAdapter, PagarmeV5CardAxiosAdapter, PagarmeV5PixAxiosAdapter, Payment, PaymentError, PaymentFirestoreRepository, PaymentMethods, PaymentProviderFactory, PaymentProviders, PaymentTransaction, PaymentType, PersonTypes, Plans, Product, ProductCatalogHasuraGraphQL, ProductCatalogHasuraGraphQLRepository, ProductErrors, ProductErrorsHasuraGraphQL, ProductErrorsHasuraGraphQLRepository, ProductFirestoreRepository, ProductGroup, ProductGroupHasuraGraphQLRepository, ProductHasuraGraphQL, ProductHasuraGraphQLRepository, ProductLabelEnum, ProductPriceLog, ProductPriceLogHasuraGraphQLRepository, ProductReview, ProductReviewHasuraGraphQLRepository, ProductSpents, ProductStockEntry, ProductStockEntryHasuraGraphQL, ProductStockEntryHasuraGraphQLRepository, ProductStockNotification, ProductStockNotificationHasuraGraphQLRepository, ProductVariantFirestoreRepository, ProductsIndex, ProductsVertexSearch, QuestionsFilters, RecoveryPassword, ReflectHelper, Register, RegisterFirebaseAuthService, RequiredArgumentError, RestCacheAdapter, RoundProductPricesHelper, Sequence, SequenceFirestoreRepository, ShippingMethod, ShopConfigs, ShopConfigsFirestoreRepository, ShopMenu, ShopMenuFirestoreRepository, ShopPageName, ShopSettings, ShopSettingsFirestoreRepository, ShoppingRecurrence, ShoppingRecurrenceCycle, ShoppingRecurrenceEdition, ShoppingRecurrenceEditionFirestoreRepository, ShoppingRecurrenceEditionStatus, ShoppingRecurrenceErrorLog, ShoppingRecurrenceErrorLogFirestoreRepository, ShoppingRecurrenceFirestoreRepository, ShoppingRecurrenceStatus, Shops, SignInMethods, SignOut, Status, StockLimitError, StockOutError, Subscription, SubscriptionEditionFirestoreRepository, SubscriptionFirestoreRepository, SubscriptionMaterialization, SubscriptionMaterializationFirestoreRepository, SubscriptionPayment, SubscriptionPaymentFirestoreRepository, SubscriptionPlan, SubscriptionPlanFirestoreRepository, SubscriptionProductFirestoreRepository, SubscriptionSummary, SubscriptionSummaryFirestoreRepository, Trace, TransactionPaymentMethods, UnauthorizedError, UpdateOptionActions, UpdateUserImage, User, UserAddress, UserAddressFirestoreRepository, UserAlreadyRegisteredError, UserBeautyProfileFirestoreRepository, UserFirestoreRepository, UserPaymentMethod, UserPaymentMethodFirestoreRepository, UserType, Variant, VariantHasuraGraphQL, VariantHasuraGraphQLRepository, VertexAxiosAdapter, WeakPasswordError, Where, Wishlist, WishlistHasuraGraphQLRepository, WishlistLogType, deserialize, getClass, is, isDebuggable, isUUID, parseDateTime, registerClass, resolveAntifraudVolumeLimits, resolveCacheConfig, resolveClass, serialize, toCents, withCreateFirestore, withCreateHasuraGraphQL, withCrudFirestore, withCrudHasuraGraphQL, withDeleteFirestore, withDeleteHasuraGraphQL, withFindFirestore, withFindHasuraGraphQL, withFirestore, withGetFirestore, withGetHasuraGraphQL, withHasuraGraphQL, withHelpers, withSubCollection, withUpdateFirestore, withUpdateHasuraGraphQL };
|
package/package.json
CHANGED
|
@@ -12,6 +12,11 @@ export declare class ShopConfigs extends BaseModel<ShopConfigs> {
|
|
|
12
12
|
subscriber: LimitOrders;
|
|
13
13
|
nonSubscriber: LimitOrders;
|
|
14
14
|
};
|
|
15
|
+
/** Falhas/bloqueios internos por dia (além de compras dia/semana). */
|
|
16
|
+
blockedAttemptsDay: {
|
|
17
|
+
subscriber: number;
|
|
18
|
+
nonSubscriber: number;
|
|
19
|
+
};
|
|
15
20
|
};
|
|
16
21
|
sameDayNotAvaliable?: ShopSameDayNotAvailable;
|
|
17
22
|
static get identifiersFields(): GenericIdentifier[];
|
|
@@ -1,17 +1,42 @@
|
|
|
1
|
+
import { ShopConfigs, ShopConfigsRepository } from '../../shop-settings';
|
|
1
2
|
import { AntifraudProvider } from '../interfaces';
|
|
2
3
|
import { Checkout } from '../models';
|
|
3
4
|
import { OrderBlockedRepository, OrderRepository } from '../repositories';
|
|
4
5
|
import { PaymentCardInfo } from '../types';
|
|
6
|
+
type LimitOrders = {
|
|
7
|
+
cpf: number;
|
|
8
|
+
email: number;
|
|
9
|
+
phone: number;
|
|
10
|
+
zip: number;
|
|
11
|
+
card?: number;
|
|
12
|
+
};
|
|
13
|
+
type ResolvedAntifraudVolumeLimits = {
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
source: 'config' | 'fallback';
|
|
16
|
+
day: {
|
|
17
|
+
subscriber: LimitOrders;
|
|
18
|
+
nonSubscriber: LimitOrders;
|
|
19
|
+
};
|
|
20
|
+
week: {
|
|
21
|
+
subscriber: LimitOrders;
|
|
22
|
+
nonSubscriber: LimitOrders;
|
|
23
|
+
};
|
|
24
|
+
blockedAttemptsDay: {
|
|
25
|
+
subscriber: number;
|
|
26
|
+
nonSubscriber: number;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
/** Defaults personalizáveis via shopConfigs.antifraude; usados só como fallback. */
|
|
30
|
+
export declare const DEFAULT_ANTIFRAUD_VOLUME_LIMITS: ResolvedAntifraudVolumeLimits;
|
|
31
|
+
/** Expõe resolução para testes; config inválida → fallback (comportamento atual). */
|
|
32
|
+
export declare function resolveAntifraudVolumeLimits(antifraude: ShopConfigs['antifraude'] | undefined | null): ResolvedAntifraudVolumeLimits;
|
|
5
33
|
export declare class AntifraudCardService implements AntifraudProvider {
|
|
6
34
|
private readonly orderRepository;
|
|
7
35
|
private readonly orderBlockedRepository;
|
|
8
|
-
private
|
|
9
|
-
|
|
10
|
-
private LIMIT_BLOCKED_ORDERS_DAY;
|
|
11
|
-
constructor(orderRepository: OrderRepository, orderBlockedRepository: OrderBlockedRepository);
|
|
36
|
+
private readonly shopConfigsRepository?;
|
|
37
|
+
constructor(orderRepository: OrderRepository, orderBlockedRepository: OrderBlockedRepository, shopConfigsRepository?: ShopConfigsRepository);
|
|
12
38
|
validate(checkout: Checkout, card: PaymentCardInfo): Promise<Boolean>;
|
|
13
|
-
private
|
|
14
|
-
private getLimitsByUserType;
|
|
39
|
+
private loadResolvedLimits;
|
|
15
40
|
private validateBlockedOrderAttempts;
|
|
16
41
|
private validateDayAndWeekOrderLimits;
|
|
17
42
|
private verifyBlockedOrderAttempts;
|
|
@@ -35,3 +60,4 @@ export declare class AntifraudCardService implements AntifraudProvider {
|
|
|
35
60
|
private countOrdersByField;
|
|
36
61
|
private getDateRange;
|
|
37
62
|
}
|
|
63
|
+
export {};
|