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.io.Serial;
019import java.util.ArrayList;
020import java.util.Collections;
021import java.util.List;
022import java.util.Optional;
023
024import org.bouncycastle.i18n.ErrorBundle;
025import org.bouncycastle.i18n.LocalizedException;
026import org.shredzone.acme4j.exception.AcmeException;
027
028/**
029 * This exception is thrown when the challenge email message is invalid.
030 * <p>
031 * If this exception is thrown, the challenge message does not match the actual challenge
032 * or has other issues. It <em>must</em> be rejected.
033 * <p>
034 * Reasons may be (for example):
035 * <ul>
036 *     <li>Unexpected sender address</li>
037 *     <li>Bad S/MIME signature</li>
038 * </ul>
039 *
040 * @since 2.15
041 */
042public class AcmeInvalidMessageException extends AcmeException {
043    @Serial
044    private static final long serialVersionUID = 5607857024718309330L;
045
046    private final List<ErrorBundle> errors;
047
048    /**
049     * Creates a new {@link AcmeInvalidMessageException}.
050     *
051     * @param msg
052     *         Reason of the exception
053     */
054    public AcmeInvalidMessageException(String msg) {
055        super(msg);
056        this.errors = Collections.emptyList();
057    }
058
059    /**
060     * Creates a new {@link AcmeInvalidMessageException}.
061     *
062     * @param msg
063     *         Reason of the exception
064     * @param errors
065     *         List of {@link ErrorBundle} with further details
066     * @since 2.16
067     */
068    public AcmeInvalidMessageException(String msg, List<ErrorBundle> errors) {
069        super(msg);
070        this.errors = unmodifiableList(errors);
071    }
072
073    /**
074     * Creates a new {@link AcmeInvalidMessageException}.
075     *
076     * @param msg
077     *         Reason of the exception
078     * @param cause
079     *         Cause
080     */
081    public AcmeInvalidMessageException(String msg, Throwable cause) {
082        super(msg, cause);
083        var errors = new ArrayList<ErrorBundle>(1);
084        Optional.ofNullable(cause)
085                .filter(LocalizedException.class::isInstance)
086                .map(LocalizedException.class::cast)
087                .map(LocalizedException::getErrorMessage)
088                .ifPresent(errors::add);
089        this.errors = unmodifiableList(errors);
090    }
091
092    /**
093     * Returns a list with further error details, if available. The list may be empty, but
094     * is never {@code null}.
095     *
096     * @since 2.16
097     */
098    public List<ErrorBundle> getErrors() {
099        return errors;
100    }
101
102}