001/*
002 * acme4j - Java ACME client
003 *
004 * Copyright (C) 2022 Richard "Shred" K├Ârber
005 *   http://acme4j.shredzone.org
006 *
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
013 */
014package org.shredzone.acme4j.smime.exception;
015
016import static java.util.Collections.unmodifiableList;
017
018import java.util.ArrayList;
019import java.util.Collections;
020import java.util.List;
021import java.util.Optional;
022
023import org.bouncycastle.i18n.ErrorBundle;
024import org.bouncycastle.i18n.LocalizedException;
025import org.shredzone.acme4j.exception.AcmeException;
026
027/**
028 * This exception is thrown when the challenge email message is invalid.
029 * <p>
030 * If this exception is thrown, the challenge message does not match the actual challenge
031 * or has other issues. It <em>must</em> be rejected.
032 * <p>
033 * Reasons may be (for example):
034 * <ul>
035 *     <li>Unexpected sender address</li>
036 *     <li>Bad S/MIME signature</li>
037 * </ul>
038 *
039 * @since 2.15
040 */
041public class AcmeInvalidMessageException extends AcmeException {
042    private static final long serialVersionUID = 5607857024718309330L;
043
044    private final List<ErrorBundle> errors;
045
046    /**
047     * Creates a new {@link AcmeInvalidMessageException}.
048     *
049     * @param msg
050     *         Reason of the exception
051     */
052    public AcmeInvalidMessageException(String msg) {
053        super(msg);
054        this.errors = Collections.emptyList();
055    }
056
057    /**
058     * Creates a new {@link AcmeInvalidMessageException}.
059     *
060     * @param msg
061     *         Reason of the exception
062     * @param errors
063     *         List of {@link ErrorBundle} with further details
064     * @since 2.16
065     */
066    public AcmeInvalidMessageException(String msg, List<ErrorBundle> errors) {
067        super(msg);
068        this.errors = unmodifiableList(errors);
069    }
070
071    /**
072     * Creates a new {@link AcmeInvalidMessageException}.
073     *
074     * @param msg
075     *         Reason of the exception
076     * @param cause
077     *         Cause
078     */
079    public AcmeInvalidMessageException(String msg, Throwable cause) {
080        super(msg, cause);
081        var errors = new ArrayList<ErrorBundle>(1);
082        Optional.ofNullable(cause)
083                .filter(LocalizedException.class::isInstance)
084                .map(LocalizedException.class::cast)
085                .map(LocalizedException::getErrorMessage)
086                .ifPresent(errors::add);
087        this.errors = unmodifiableList(errors);
088    }
089
090    /**
091     * Returns a list with further error details, if available. The list may be empty, but
092     * is never {@code null}.
093     *
094     * @since 2.16
095     */
096    public List<ErrorBundle> getErrors() {
097        return errors;
098    }
099
100}