com.google.gerrit.server.mail.send.FromAddressGeneratorProvider.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gerrit.server.mail.send.FromAddressGeneratorProvider.java

Source

// Copyright (C) 2009 The Android Open Source Project
//
// Licensed 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 com.google.gerrit.server.mail.send;

import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.gerrit.common.data.ParameterizedString;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.mail.Address;
import com.google.gerrit.server.mail.MailUtil;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.regex.Pattern;
import org.apache.commons.codec.binary.Base64;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.PersonIdent;

/** Creates a {@link FromAddressGenerator} from the {@link GerritServerConfig} */
@Singleton
public class FromAddressGeneratorProvider implements Provider<FromAddressGenerator> {
    private final FromAddressGenerator generator;

    @Inject
    FromAddressGeneratorProvider(@GerritServerConfig final Config cfg,
            @AnonymousCowardName final String anonymousCowardName, @GerritPersonIdent final PersonIdent myIdent,
            final AccountCache accountCache) {

        final String from = cfg.getString("sendemail", null, "from");
        final Address srvAddr = toAddress(myIdent);

        if (from == null || "MIXED".equalsIgnoreCase(from)) {
            ParameterizedString name = new ParameterizedString("${user} (Code Review)");
            generator = new PatternGen(srvAddr, accountCache, anonymousCowardName, name, srvAddr.getEmail());
        } else if ("USER".equalsIgnoreCase(from)) {
            String[] domains = cfg.getStringList("sendemail", null, "allowedDomain");
            Pattern domainPattern = MailUtil.glob(domains);
            ParameterizedString namePattern = new ParameterizedString("${user} (Code Review)");
            generator = new UserGen(accountCache, domainPattern, anonymousCowardName, namePattern, srvAddr);
        } else if ("SERVER".equalsIgnoreCase(from)) {
            generator = new ServerGen(srvAddr);
        } else {
            final Address a = Address.parse(from);
            final ParameterizedString name = a.getName() != null ? new ParameterizedString(a.getName()) : null;
            if (name == null || name.getParameterNames().isEmpty()) {
                generator = new ServerGen(a);
            } else {
                generator = new PatternGen(srvAddr, accountCache, anonymousCowardName, name, a.getEmail());
            }
        }
    }

    private static Address toAddress(final PersonIdent myIdent) {
        return new Address(myIdent.getName(), myIdent.getEmailAddress());
    }

    @Override
    public FromAddressGenerator get() {
        return generator;
    }

    static final class UserGen implements FromAddressGenerator {
        private final AccountCache accountCache;
        private final Pattern domainPattern;
        private final String anonymousCowardName;
        private final ParameterizedString nameRewriteTmpl;
        private final Address serverAddress;

        /**
         * From address generator for USER mode
         *
         * @param accountCache get user account from id
         * @param domainPattern allowed user domain pattern that Gerrit can send as the user
         * @param anonymousCowardName name used when user's full name is missing
         * @param nameRewriteTmpl name template used for rewriting the sender's name when Gerrit can not
         *     send as the user
         * @param serverAddress serverAddress.name is used when fromId is null and serverAddress.email
         *     is used when Gerrit can not send as the user
         */
        UserGen(AccountCache accountCache, Pattern domainPattern, String anonymousCowardName,
                ParameterizedString nameRewriteTmpl, Address serverAddress) {
            this.accountCache = accountCache;
            this.domainPattern = domainPattern;
            this.anonymousCowardName = anonymousCowardName;
            this.nameRewriteTmpl = nameRewriteTmpl;
            this.serverAddress = serverAddress;
        }

        @Override
        public boolean isGenericAddress(Account.Id fromId) {
            return false;
        }

        @Override
        public Address from(final Account.Id fromId) {
            String senderName;
            if (fromId != null) {
                Account a = accountCache.get(fromId).getAccount();
                String fullName = a.getFullName();
                String userEmail = a.getPreferredEmail();
                if (canRelay(userEmail)) {
                    return new Address(fullName, userEmail);
                }

                if (fullName == null || "".equals(fullName.trim())) {
                    fullName = anonymousCowardName;
                }
                senderName = nameRewriteTmpl.replace("user", fullName).toString();
            } else {
                senderName = serverAddress.getName();
            }

            String senderEmail;
            ParameterizedString senderEmailPattern = new ParameterizedString(serverAddress.getEmail());
            if (senderEmailPattern.getParameterNames().isEmpty()) {
                senderEmail = senderEmailPattern.getRawPattern();
            } else {
                senderEmail = senderEmailPattern.replace("userHash", hashOf(senderName)).toString();
            }
            return new Address(senderName, senderEmail);
        }

        /** check if Gerrit is allowed to send from {@code userEmail}. */
        private boolean canRelay(String userEmail) {
            if (userEmail != null) {
                int index = userEmail.indexOf('@');
                if (index > 0 && index < userEmail.length() - 1) {
                    return domainPattern.matcher(userEmail.substring(index + 1)).matches();
                }
            }
            return false;
        }
    }

    static final class ServerGen implements FromAddressGenerator {
        private final Address srvAddr;

        ServerGen(Address srvAddr) {
            this.srvAddr = srvAddr;
        }

        @Override
        public boolean isGenericAddress(Account.Id fromId) {
            return true;
        }

        @Override
        public Address from(final Account.Id fromId) {
            return srvAddr;
        }
    }

    static final class PatternGen implements FromAddressGenerator {
        private final ParameterizedString senderEmailPattern;
        private final Address serverAddress;
        private final AccountCache accountCache;
        private final String anonymousCowardName;
        private final ParameterizedString namePattern;

        PatternGen(final Address serverAddress, final AccountCache accountCache, final String anonymousCowardName,
                final ParameterizedString namePattern, final String senderEmail) {
            this.senderEmailPattern = new ParameterizedString(senderEmail);
            this.serverAddress = serverAddress;
            this.accountCache = accountCache;
            this.anonymousCowardName = anonymousCowardName;
            this.namePattern = namePattern;
        }

        @Override
        public boolean isGenericAddress(Account.Id fromId) {
            return false;
        }

        @Override
        public Address from(final Account.Id fromId) {
            final String senderName;

            if (fromId != null) {
                final Account account = accountCache.get(fromId).getAccount();
                String fullName = account.getFullName();
                if (fullName == null || "".equals(fullName)) {
                    fullName = anonymousCowardName;
                }
                senderName = namePattern.replace("user", fullName).toString();

            } else {
                senderName = serverAddress.getName();
            }

            String senderEmail;
            if (senderEmailPattern.getParameterNames().isEmpty()) {
                senderEmail = senderEmailPattern.getRawPattern();
            } else {
                senderEmail = senderEmailPattern.replace("userHash", hashOf(senderName)).toString();
            }
            return new Address(senderName, senderEmail);
        }
    }

    private static String hashOf(String data) {
        try {
            MessageDigest hash = MessageDigest.getInstance("MD5");
            byte[] bytes = hash.digest(data.getBytes(UTF_8));
            return Base64.encodeBase64URLSafeString(bytes);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("No MD5 available", e);
        }
    }
}