| /**************************************************************** |
| * Licensed to the Apache Software Foundation (ASF) under one * |
| * or more contributor license agreements. See the NOTICE file * |
| * distributed with this work for additional information * |
| * regarding copyright ownership. The ASF licenses this file * |
| * to you under the Apache License, Version 2.0 (the * |
| * "License"); you may not use this file except in compliance * |
| * with the License. You may obtain a copy of the License at * |
| * * |
| * http://www.apache.org/licenses/LICENSE-2.0 * |
| * * |
| * Unless required by applicable law or agreed to in writing, * |
| * software distributed under the License is distributed on an * |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * |
| * KIND, either express or implied. See the License for the * |
| * specific language governing permissions and limitations * |
| * under the License. * |
| ****************************************************************/ |
| package org.apache.james.droplists.memory; |
| |
| import org.apache.james.core.MailAddress; |
| import org.apache.james.droplists.api.DeniedEntityType; |
| import org.apache.james.droplists.api.DropList; |
| import org.apache.james.droplists.api.DropListEntry; |
| import org.apache.james.droplists.api.OwnerScope; |
| |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.HashMultimap; |
| import com.google.common.collect.Multimap; |
| import com.google.common.collect.Multimaps; |
| |
| import reactor.core.publisher.Flux; |
| import reactor.core.publisher.Mono; |
| |
| public class MemoryDropList implements DropList { |
| |
| private final Multimap<OwnerScope, DropListEntry> globalDropList = Multimaps.synchronizedMultimap(HashMultimap.create()); |
| private final Multimap<OwnerScope, DropListEntry> domainDropList = Multimaps.synchronizedMultimap(HashMultimap.create()); |
| private final Multimap<OwnerScope, DropListEntry> userDropList = Multimaps.synchronizedMultimap(HashMultimap.create()); |
| |
| @Override |
| public Mono<Void> add(DropListEntry entry) { |
| Preconditions.checkArgument(entry != null); |
| OwnerScope ownerScope = entry.getOwnerScope(); |
| Multimap<OwnerScope, DropListEntry> selectedDropList = getDropListByScope(ownerScope); |
| return Mono.fromRunnable(() -> selectedDropList.put(ownerScope, entry)); |
| } |
| |
| @Override |
| public Mono<Void> remove(DropListEntry entry) { |
| Preconditions.checkArgument(entry != null); |
| OwnerScope ownerScope = entry.getOwnerScope(); |
| Multimap<OwnerScope, DropListEntry> selectedDropList = getDropListByScope(ownerScope); |
| return Mono.fromRunnable(() -> selectedDropList.remove(ownerScope, entry)); |
| } |
| |
| @Override |
| public Flux<DropListEntry> list(OwnerScope ownerScope, String owner) { |
| Preconditions.checkArgument(ownerScope != null); |
| Preconditions.checkArgument(owner != null); |
| Multimap<OwnerScope, DropListEntry> selectedDropList = getDropListByScope(ownerScope); |
| return Flux.fromIterable(selectedDropList.get(ownerScope)) |
| .filter(entry -> entry.getOwner().equals(owner)); |
| } |
| |
| @Override |
| public Mono<Status> query(OwnerScope ownerScope, String owner, MailAddress sender) { |
| Preconditions.checkArgument(ownerScope != null); |
| Preconditions.checkArgument(owner != null); |
| Preconditions.checkArgument(sender != null); |
| Multimap<OwnerScope, DropListEntry> selectedDropList = getDropListByScope(ownerScope); |
| boolean isBlocked = selectedDropList.get(ownerScope).stream() |
| .anyMatch(entry -> isEntryMatchingOwner(ownerScope, owner, entry) && isEntryMatchingDeniedEntity(sender, entry)); |
| |
| return Mono.just(isBlocked ? Status.BLOCKED : Status.ALLOWED); |
| } |
| |
| private Multimap<OwnerScope, DropListEntry> getDropListByScope(OwnerScope ownerScope) { |
| return switch (ownerScope) { |
| case GLOBAL -> globalDropList; |
| case DOMAIN -> domainDropList; |
| case USER -> userDropList; |
| }; |
| } |
| |
| private boolean isEntryMatchingOwner(OwnerScope ownerScope, String owner, DropListEntry entry) { |
| if (ownerScope.equals(OwnerScope.GLOBAL)) { |
| return true; |
| } else { |
| return entry.getOwner().equals(owner); |
| } |
| } |
| |
| private boolean isEntryMatchingDeniedEntity(MailAddress sender, DropListEntry entry) { |
| String entityFromSender = entry.getDeniedEntityType() == DeniedEntityType.DOMAIN ? sender.getDomain().asString() : sender.asString(); |
| |
| return entry.getDeniedEntity().equals(entityFromSender); |
| } |
| } |