| | |
| | | /** Final API boundary for APP traffic, including responses returned by every service. */ |
| | | @Component |
| | | public class SensitiveDataMaskingGlobalFilter implements GlobalFilter, Ordered { |
| | | /** |
| | | * This response contains the current user's own phone number, which the APP |
| | | * needs in its original form. The account service marks the field with |
| | | * {@code @UnmaskedSensitiveData}; the gateway works on JSON text, so it |
| | | * must mirror that narrow exception here. |
| | | */ |
| | | private static final String UNMASKED_USER_DETAILS_PATH = "/account/api/useBenefit/userDetails"; |
| | | private static final Pattern FIELD = Pattern.compile("(?i)(\\\"(?:[a-z]*phone|[a-z]*mobile|telephone|tel)\\\"\\s*:\\s*\\\")([^\\\"]*)(\\\")"); |
| | | private static final Pattern IDCARD = Pattern.compile("(?i)(\\\"(?:[a-z]*idcard|[a-z]*identitycard|identitynumber|idnumber)\\\"\\s*:\\s*\\\")([^\\\"]*)(\\\")"); |
| | | |
| | |
| | | |
| | | @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { |
| | | // This route itself enforces the admin check and writes an audit record. |
| | | String path = exchange.getRequest().getURI().getPath(); |
| | | if (path.startsWith("/system/sensitive/") || UNMASKED_USER_DETAILS_PATH.equals(path)) return chain.filter(exchange); |
| | | if (exchange.getRequest().getURI().getPath().startsWith("/system/sensitive/")) return chain.filter(exchange); |
| | | ServerHttpResponseDecorator decorated = new ServerHttpResponseDecorator(exchange.getResponse()) { |
| | | @Override public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { |
| | | MediaType type = getHeaders().getContentType(); |