001/*
002 * acme4j - Java ACME client
003 *
004 * Copyright (C) 2016 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;
015
016import static java.util.stream.Collectors.toList;
017
018import java.net.URI;
019import java.net.URL;
020import java.time.Duration;
021import java.util.Collection;
022import java.util.Optional;
023
024import org.shredzone.acme4j.exception.AcmeNotSupportedException;
025import org.shredzone.acme4j.toolbox.JSON;
026import org.shredzone.acme4j.toolbox.JSON.Value;
027
028/**
029 * A collection of metadata related to the CA provider.
030 */
031public class Metadata {
032
033    private final JSON meta;
034
035    /**
036     * Creates a new {@link Metadata} instance.
037     *
038     * @param meta
039     *            JSON map of metadata
040     */
041    public Metadata(JSON meta) {
042        this.meta = meta;
043    }
044
045    /**
046     * Returns an {@link URI} of the current terms of service, or empty if not available.
047     */
048    public Optional<URI> getTermsOfService() {
049        return meta.get("termsOfService").map(Value::asURI);
050    }
051
052    /**
053     * Returns an {@link URL} of a website providing more information about the ACME
054     * server. Empty if not available.
055     */
056    public Optional<URL> getWebsite() {
057        return meta.get("website").map(Value::asURL);
058    }
059
060    /**
061     * Returns a collection of hostnames, which the ACME server recognises as referring to
062     * itself for the purposes of CAA record validation. Empty if not available.
063     */
064    public Collection<String> getCaaIdentities() {
065        return meta.get("caaIdentities")
066                .asArray()
067                .stream()
068                .map(Value::asString)
069                .collect(toList());
070    }
071
072    /**
073     * Returns whether an external account is required by this CA.
074     */
075    public boolean isExternalAccountRequired() {
076        return meta.get("externalAccountRequired").map(Value::asBoolean).orElse(false);
077    }
078
079    /**
080     * Returns whether the CA supports short-term auto-renewal of certificates.
081     *
082     * @since 2.3
083     */
084    public boolean isAutoRenewalEnabled() {
085        return meta.get("auto-renewal").isPresent();
086    }
087
088    /**
089     * Returns the minimum acceptable value for the maximum validity of a certificate
090     * before auto-renewal.
091     *
092     * @since 2.3
093     * @throws AcmeNotSupportedException if the server does not support auto-renewal.
094     */
095    public Duration getAutoRenewalMinLifetime() {
096        return meta.getFeature("auto-renewal")
097                .map(Value::asObject)
098                .orElseGet(JSON::empty)
099                .get("min-lifetime")
100                .asDuration();
101    }
102
103    /**
104     * Returns the maximum delta between auto-renewal end date and auto-renewal start
105     * date.
106     *
107     * @since 2.3
108     * @throws AcmeNotSupportedException if the server does not support auto-renewal.
109     */
110    public Duration getAutoRenewalMaxDuration() {
111        return meta.getFeature("auto-renewal")
112                .map(Value::asObject)
113                .orElseGet(JSON::empty)
114                .get("max-duration")
115                .asDuration();
116    }
117
118    /**
119     * Returns whether the CA also allows to fetch STAR certificates via GET request.
120     *
121     * @since 2.6
122     * @throws AcmeNotSupportedException if the server does not support auto-renewal.
123     */
124    public boolean isAutoRenewalGetAllowed() {
125        return meta.getFeature("auto-renewal").optional()
126                .map(Value::asObject)
127                .orElseGet(JSON::empty)
128                .get("allow-certificate-get")
129                .optional()
130                .map(Value::asBoolean)
131                .orElse(false);
132    }
133
134    /**
135     * Returns whether the CA supports subdomain auth according to RFC9444.
136     *
137     * @since 3.3.0
138     */
139    public boolean isSubdomainAuthAllowed() {
140        return meta.get("subdomainAuthAllowed").map(Value::asBoolean).orElse(false);
141    }
142
143    /**
144     * Returns the JSON representation of the metadata. This is useful for reading
145     * proprietary metadata properties.
146     */
147    public JSON getJSON() {
148        return meta;
149    }
150
151}