mirror of
https://github.com/certbot/certbot.git
synced 2026-08-03 00:22:04 +02:00
Document newly-added functions and methods
This commit is contained in:
+10
-5
@@ -60,7 +60,7 @@ def unique_file(path, mode=0o777):
|
|||||||
:param str path: path/filename.ext
|
:param str path: path/filename.ext
|
||||||
:param int mode: File mode
|
:param int mode: File mode
|
||||||
|
|
||||||
:return: tuple of file object and file name
|
:returns: tuple of file object and file name
|
||||||
|
|
||||||
"""
|
"""
|
||||||
path, tail = os.path.split(path)
|
path, tail = os.path.split(path)
|
||||||
@@ -79,11 +79,16 @@ def unique_lineage_name(path, filename, mode=0o777):
|
|||||||
"""Safely finds a unique file for writing only (by default). Uses a
|
"""Safely finds a unique file for writing only (by default). Uses a
|
||||||
file lineage convention.
|
file lineage convention.
|
||||||
|
|
||||||
:param str path: path
|
:param str path: directory path
|
||||||
:param str filename: filename
|
:param str filename: proposed filename
|
||||||
:param int mode: File mode
|
:param int mode: file mode
|
||||||
|
|
||||||
:return: tuple of file object and file name
|
:returns: tuple of file object and file name (which may be modified from
|
||||||
|
the requested one by appending digits to ensure uniqueness)
|
||||||
|
|
||||||
|
:raises OSError: if writing files fails for an unanticipated reason,
|
||||||
|
such as a full disk or a lack of permission to write to specified
|
||||||
|
location.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
fname = os.path.join(path, "%s.conf" % (filename))
|
fname = os.path.join(path, "%s.conf" % (filename))
|
||||||
|
|||||||
+13
-3
@@ -32,8 +32,18 @@ class AttrDict(dict):
|
|||||||
|
|
||||||
|
|
||||||
def renew(cert, old_version):
|
def renew(cert, old_version):
|
||||||
"""Perform automated renewal of the referenced cert, if possible."""
|
"""Perform automated renewal of the referenced cert, if possible.
|
||||||
# TODO: handle partial success
|
|
||||||
|
:param class:`letsencrypt.storage.RenewableCert` cert: the certificate
|
||||||
|
lineage to attempt to renew.
|
||||||
|
:param int old_version: the version of the certificate lineage relative
|
||||||
|
to which the renewal should be attempted.
|
||||||
|
|
||||||
|
:returns: int referring to newly created version of this cert lineage,
|
||||||
|
or False if renewal was not successful."""
|
||||||
|
|
||||||
|
# TODO: handle partial success (some names can be renewed but not
|
||||||
|
# others)
|
||||||
# TODO: handle obligatory key rotation vs. optional key rotation vs.
|
# TODO: handle obligatory key rotation vs. optional key rotation vs.
|
||||||
# requested key rotation
|
# requested key rotation
|
||||||
if "renewalparams" not in cert.configfile:
|
if "renewalparams" not in cert.configfile:
|
||||||
@@ -106,7 +116,7 @@ def main(config=DEFAULTS):
|
|||||||
continue
|
continue
|
||||||
if cert.should_autodeploy():
|
if cert.should_autodeploy():
|
||||||
cert.update_all_links_to(cert.latest_common_version())
|
cert.update_all_links_to(cert.latest_common_version())
|
||||||
# TODO: restart web server
|
# TODO: restart web server (invoke IInstaller.restart() method)
|
||||||
notify.notify("Autodeployed a cert!!!", "root", "It worked!")
|
notify.notify("Autodeployed a cert!!!", "root", "It worked!")
|
||||||
# TODO: explain what happened
|
# TODO: explain what happened
|
||||||
if cert.should_autorenew():
|
if cert.should_autorenew():
|
||||||
|
|||||||
+251
-61
@@ -23,12 +23,19 @@ ALL_FOUR = ("cert", "privkey", "chain", "fullchain")
|
|||||||
|
|
||||||
|
|
||||||
def parse_time_interval(interval, textparser=parsedatetime.Calendar()):
|
def parse_time_interval(interval, textparser=parsedatetime.Calendar()):
|
||||||
"""Parse the time specified time interval, which can be in the
|
"""Parse the time specified time interval.
|
||||||
English-language format understood by parsedatetime, e.g., '10 days',
|
|
||||||
'3 weeks', '6 months', '9 hours', or a sequence of such intervals
|
The interval can be in the English-language format understood by
|
||||||
like '6 months 1 week' or '3 days 12 hours'. If an integer is found
|
parsedatetime, e.g., '10 days', '3 weeks', '6 months', '9 hours',
|
||||||
with no associated unit, it is interpreted by default as a number of
|
or a sequence of such intervals like '6 months 1 week' or '3 days
|
||||||
days."""
|
12 hours'. If an integer is found with no associated unit, it is
|
||||||
|
interpreted by default as a number of days.
|
||||||
|
|
||||||
|
:param str interval: the time interval to parse.
|
||||||
|
|
||||||
|
:returns: the interpretation of the time interval.
|
||||||
|
:rtype: :class:`datetime.timedelta`"""
|
||||||
|
|
||||||
if interval.strip().isdigit():
|
if interval.strip().isdigit():
|
||||||
interval += " days"
|
interval += " days"
|
||||||
return datetime.timedelta(0, time.mktime(textparser.parse(
|
return datetime.timedelta(0, time.mktime(textparser.parse(
|
||||||
@@ -38,9 +45,57 @@ def parse_time_interval(interval, textparser=parsedatetime.Calendar()):
|
|||||||
class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
||||||
"""Represents a lineage of certificates that is under the management
|
"""Represents a lineage of certificates that is under the management
|
||||||
of the Let's Encrypt client, indicated by the existence of an
|
of the Let's Encrypt client, indicated by the existence of an
|
||||||
associated renewal configuration file."""
|
associated renewal configuration file.
|
||||||
|
|
||||||
|
Note that the notion of "current version" for a lineage is maintained
|
||||||
|
on disk in the structure of symbolic links, and is not explicitly
|
||||||
|
stored in any instance variable in this object. The RenewableCert
|
||||||
|
object is able to determine information about the current (or other)
|
||||||
|
version by accessing data on disk, but does not inherently know any
|
||||||
|
of this information except by examining the symbolic links as needed.
|
||||||
|
The instance variables mentioned below point to symlinks that reflect
|
||||||
|
the notion of "current version" of each managed object, and it is
|
||||||
|
these paths that should be used when configuring servers to use the
|
||||||
|
certificate managed in a lineage. These paths are normally within
|
||||||
|
the "live" directory, and their symlink targets -- the actual cert
|
||||||
|
files -- are normally found within the "archive" directory.
|
||||||
|
|
||||||
|
:ivar cert: The path to the symlink representing the current version
|
||||||
|
of the certificate managed by this lineage.
|
||||||
|
:type cert: str
|
||||||
|
|
||||||
|
:ivar privkey: The path to the symlink representing the current version
|
||||||
|
of the private key managed by this lineage.
|
||||||
|
:type privkey: str
|
||||||
|
|
||||||
|
:ivar chain: The path to the symlink representing the current version
|
||||||
|
of the chain managed by this lineage.
|
||||||
|
:type chain: str
|
||||||
|
|
||||||
|
:ivar fullchain: The path to the symlink representing the current version
|
||||||
|
of the fullchain (combined chain and cert) managed by this lineage.
|
||||||
|
:type fullchain: str
|
||||||
|
|
||||||
|
:ivar configuration: The renewal configuration options associated with
|
||||||
|
this lineage, obtained from parsing the renewal configuration file
|
||||||
|
and/or systemwide defaults.
|
||||||
|
:type configuration: :class:`configobj.ConfigObj`"""
|
||||||
|
|
||||||
def __init__(self, configfile, defaults=DEFAULTS):
|
def __init__(self, configfile, defaults=DEFAULTS):
|
||||||
|
"""Instantiate a RenewableCert object from an existing lineage.
|
||||||
|
|
||||||
|
:param :class:`configobj.ConfigObj` configfile: an already-parsed
|
||||||
|
ConfigObj object made from reading the renewal config file that
|
||||||
|
defines this lineage.
|
||||||
|
:param :class:`configobj.ConfigObj` defaults: systemwide defaults
|
||||||
|
for renewal properties not otherwise specified in the individual
|
||||||
|
renewal config file.
|
||||||
|
|
||||||
|
:raises ValueError: if the configuration file's name didn't end in
|
||||||
|
".conf", or the file is missing or broken.
|
||||||
|
:raises TypeError: if the provided renewal configuration isn't a
|
||||||
|
ConfigObj object."""
|
||||||
|
|
||||||
if isinstance(configfile, configobj.ConfigObj):
|
if isinstance(configfile, configobj.ConfigObj):
|
||||||
if not os.path.basename(configfile.filename).endswith(".conf"):
|
if not os.path.basename(configfile.filename).endswith(".conf"):
|
||||||
raise ValueError("renewal config file name must end in .conf")
|
raise ValueError("renewal config file name must end in .conf")
|
||||||
@@ -67,8 +122,11 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
|||||||
self.fullchain = self.configuration["fullchain"]
|
self.fullchain = self.configuration["fullchain"]
|
||||||
|
|
||||||
def consistent(self):
|
def consistent(self):
|
||||||
"""Is the structure of the archived files and links related to this
|
"""Are the files associated with this lineage self-consistent?
|
||||||
lineage correct and self-consistent?"""
|
|
||||||
|
:returns: whether the files stored in connection with this
|
||||||
|
lineage appear to be correct and consistent with one another.
|
||||||
|
:rtype: bool"""
|
||||||
|
|
||||||
# Each element must be referenced with an absolute path
|
# Each element must be referenced with an absolute path
|
||||||
if any(not os.path.isabs(x) for x in
|
if any(not os.path.isabs(x) for x in
|
||||||
@@ -120,8 +178,8 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def fix(self):
|
def fix(self):
|
||||||
"""Attempt to fix some kinds of defects or inconsistencies
|
"""Attempt to fix defects or inconsistencies in this lineage.
|
||||||
in the symlink structure, if possible."""
|
(Currently unimplemented.)"""
|
||||||
# TODO: Figure out what kinds of fixes are possible. For
|
# TODO: Figure out what kinds of fixes are possible. For
|
||||||
# example, checking if there is a valid version that
|
# example, checking if there is a valid version that
|
||||||
# we can update the symlinks to. (Maybe involve
|
# we can update the symlinks to. (Maybe involve
|
||||||
@@ -135,8 +193,14 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
|||||||
# filesystem errors, or crashes.)
|
# filesystem errors, or crashes.)
|
||||||
|
|
||||||
def current_target(self, kind):
|
def current_target(self, kind):
|
||||||
"""Returns the full path to which the link of the specified
|
"""Returns full path to which the specified item currently points.
|
||||||
kind currently points."""
|
|
||||||
|
:param str kind: the lineage member item ("cert", "privkey",
|
||||||
|
"chain", or "fullchain")
|
||||||
|
|
||||||
|
:returns: the path to the current version of the specified member.
|
||||||
|
:rtype: str"""
|
||||||
|
|
||||||
if kind not in ALL_FOUR:
|
if kind not in ALL_FOUR:
|
||||||
raise ValueError("unknown kind of item")
|
raise ValueError("unknown kind of item")
|
||||||
link = getattr(self, kind)
|
link = getattr(self, kind)
|
||||||
@@ -148,10 +212,18 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
|||||||
return target
|
return target
|
||||||
|
|
||||||
def current_version(self, kind):
|
def current_version(self, kind):
|
||||||
"""Returns the numerical version of the object to which the link
|
"""Returns numerical version of the specified item.
|
||||||
of the specified kind currently points. For example, if kind
|
|
||||||
|
For example, if kind
|
||||||
is "chain" and the current chain link points to a file named
|
is "chain" and the current chain link points to a file named
|
||||||
"chain7.pem", returns the integer 7."""
|
"chain7.pem", returns the integer 7.
|
||||||
|
|
||||||
|
:param str kind: the lineage member item ("cert", "privkey",
|
||||||
|
"chain", or "fullchain")
|
||||||
|
|
||||||
|
:returns: the current version of the specified member.
|
||||||
|
:rtype: int"""
|
||||||
|
|
||||||
if kind not in ALL_FOUR:
|
if kind not in ALL_FOUR:
|
||||||
raise ValueError("unknown kind of item")
|
raise ValueError("unknown kind of item")
|
||||||
pattern = re.compile(r"^{0}([0-9]+)\.pem$".format(kind))
|
pattern = re.compile(r"^{0}([0-9]+)\.pem$".format(kind))
|
||||||
@@ -165,18 +237,36 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def version(self, kind, version):
|
def version(self, kind, version):
|
||||||
"""Constructs the filename that would correspond to the
|
"""The filename that corresponds to the specified version and kind.
|
||||||
specified version of the specified kind of item in this
|
|
||||||
lineage. Warning: the specified version may not exist."""
|
Warning: the specified version may not exist in this lineage. There
|
||||||
|
is no guarantee that the file path returned by this method actually
|
||||||
|
exists.
|
||||||
|
|
||||||
|
:param str kind: the lineage member item ("cert", "privkey",
|
||||||
|
"chain", or "fullchain")
|
||||||
|
:param int version: the desired version
|
||||||
|
|
||||||
|
:returns: the path to the specified version of the specified member.
|
||||||
|
:rtype: str"""
|
||||||
|
|
||||||
if kind not in ALL_FOUR:
|
if kind not in ALL_FOUR:
|
||||||
raise ValueError("unknown kind of item")
|
raise ValueError("unknown kind of item")
|
||||||
where = os.path.dirname(self.current_target(kind))
|
where = os.path.dirname(self.current_target(kind))
|
||||||
return os.path.join(where, "{0}{1}.pem".format(kind, version))
|
return os.path.join(where, "{0}{1}.pem".format(kind, version))
|
||||||
|
|
||||||
def available_versions(self, kind):
|
def available_versions(self, kind):
|
||||||
"""Which alternative versions of the specified kind of item
|
"""Which alternative versions of the specified kind of item exist?
|
||||||
exist in the archive directory where the current version is
|
|
||||||
stored?"""
|
The archive directory where the current version is stored is
|
||||||
|
consulted to obtain the list of alternatives.
|
||||||
|
|
||||||
|
:param str kind: the lineage member item ("cert", "privkey",
|
||||||
|
"chain", or "fullchain")
|
||||||
|
|
||||||
|
:returns: all of the version numbers that currently exist
|
||||||
|
:rtype: list of int"""
|
||||||
|
|
||||||
if kind not in ALL_FOUR:
|
if kind not in ALL_FOUR:
|
||||||
raise ValueError("unknown kind of item")
|
raise ValueError("unknown kind of item")
|
||||||
where = os.path.dirname(self.current_target(kind))
|
where = os.path.dirname(self.current_target(kind))
|
||||||
@@ -186,13 +276,23 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
|||||||
return sorted([int(m.groups()[0]) for m in matches if m])
|
return sorted([int(m.groups()[0]) for m in matches if m])
|
||||||
|
|
||||||
def newest_available_version(self, kind):
|
def newest_available_version(self, kind):
|
||||||
"""What is the newest available version of the specified
|
"""What is the newest available version of the specified kind of item?
|
||||||
kind of item?"""
|
|
||||||
|
:param str kind: the lineage member item ("cert", "privkey",
|
||||||
|
"chain", or "fullchain")
|
||||||
|
|
||||||
|
:returns: the newest available version of this member
|
||||||
|
:rtype: int"""
|
||||||
|
|
||||||
return max(self.available_versions(kind))
|
return max(self.available_versions(kind))
|
||||||
|
|
||||||
def latest_common_version(self):
|
def latest_common_version(self):
|
||||||
"""What is the largest version number for which versions
|
"""What is the newest version for which all items are available?
|
||||||
of cert, privkey, chain, and fullchain are all available?"""
|
|
||||||
|
:returns: the newest available version for which all members (cert,
|
||||||
|
privkey, chain, and fullchain) exist
|
||||||
|
:rtype: int"""
|
||||||
|
|
||||||
# TODO: this can raise ValueError if there is no version overlap
|
# TODO: this can raise ValueError if there is no version overlap
|
||||||
# (it should probably return None instead)
|
# (it should probably return None instead)
|
||||||
# TODO: this can raise a spurious AttributeError if the current
|
# TODO: this can raise a spurious AttributeError if the current
|
||||||
@@ -201,8 +301,13 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
|||||||
return max(n for n in versions[0] if all(n in v for v in versions[1:]))
|
return max(n for n in versions[0] if all(n in v for v in versions[1:]))
|
||||||
|
|
||||||
def next_free_version(self):
|
def next_free_version(self):
|
||||||
"""What is the smallest new version number that is larger than
|
"""What is the smallest version newer than all full or partial versions?
|
||||||
any available version of any managed item?"""
|
|
||||||
|
:returns: the smallest version number that is larger than any version
|
||||||
|
of any item currently stored in this lineage
|
||||||
|
:rtype: int
|
||||||
|
"""
|
||||||
|
|
||||||
# TODO: consider locking/mutual exclusion between updating processes
|
# TODO: consider locking/mutual exclusion between updating processes
|
||||||
# This isn't self.latest_common_version() + 1 because we don't want
|
# This isn't self.latest_common_version() + 1 because we don't want
|
||||||
# collide with a version that might exist for one file type but not
|
# collide with a version that might exist for one file type but not
|
||||||
@@ -210,16 +315,28 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
|||||||
return max(self.newest_available_version(x) for x in ALL_FOUR) + 1
|
return max(self.newest_available_version(x) for x in ALL_FOUR) + 1
|
||||||
|
|
||||||
def has_pending_deployment(self):
|
def has_pending_deployment(self):
|
||||||
"""Is there a later version of all of the managed items?"""
|
"""Is there a later version of all of the managed items?
|
||||||
|
|
||||||
|
:returns: True if there is a complete version of this lineage with
|
||||||
|
a larger version number than the current version, and False
|
||||||
|
otherwise
|
||||||
|
:rtype: bool"""
|
||||||
|
|
||||||
# TODO: consider whether to assume consistency or treat
|
# TODO: consider whether to assume consistency or treat
|
||||||
# inconsistent/consistent versions differently
|
# inconsistent/consistent versions differently
|
||||||
smallest_current = min(self.current_version(x) for x in ALL_FOUR)
|
smallest_current = min(self.current_version(x) for x in ALL_FOUR)
|
||||||
return smallest_current < self.latest_common_version()
|
return smallest_current < self.latest_common_version()
|
||||||
|
|
||||||
def update_link_to(self, kind, version):
|
def update_link_to(self, kind, version):
|
||||||
"""Change the target of the link of the specified item to point
|
"""Make the specified item point at the specified version.
|
||||||
to the specified version. (Note that this method doesn't verify
|
|
||||||
that the specified version exists.)"""
|
(Note that this method doesn't verify that the specified version
|
||||||
|
exists.)
|
||||||
|
|
||||||
|
:param str kind: the lineage member item ("cert", "privkey",
|
||||||
|
"chain", or "fullchain")
|
||||||
|
:param int version: the desired version"""
|
||||||
|
|
||||||
if kind not in ALL_FOUR:
|
if kind not in ALL_FOUR:
|
||||||
raise ValueError("unknown kind of item")
|
raise ValueError("unknown kind of item")
|
||||||
link = getattr(self, kind)
|
link = getattr(self, kind)
|
||||||
@@ -236,8 +353,10 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
|||||||
os.symlink(os.path.join(target_directory, filename), link)
|
os.symlink(os.path.join(target_directory, filename), link)
|
||||||
|
|
||||||
def update_all_links_to(self, version):
|
def update_all_links_to(self, version):
|
||||||
"""Change the target of the cert, privkey, chain, and fullchain links
|
"""Change all member objects to point to the specified version.
|
||||||
to point to the specified version."""
|
|
||||||
|
:param int version: the desired version"""
|
||||||
|
|
||||||
for kind in ALL_FOUR:
|
for kind in ALL_FOUR:
|
||||||
self.update_link_to(kind, version)
|
self.update_link_to(kind, version)
|
||||||
|
|
||||||
@@ -255,23 +374,43 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
|||||||
i[8:10] + ":" + i[10:12] + ":" + i[12:])
|
i[8:10] + ":" + i[10:12] + ":" + i[12:])
|
||||||
|
|
||||||
def notbefore(self, version=None):
|
def notbefore(self, version=None):
|
||||||
"""When is the beginning validity time of the specified version of the
|
"""When does the specified cert version start being valid?
|
||||||
cert in this lineage? (If no version is specified, use the current
|
|
||||||
version.)"""
|
(If no version is specified, use the current version.)
|
||||||
|
|
||||||
|
:param int version: the desired version number
|
||||||
|
|
||||||
|
:returns: the notBefore value from the specified cert version in this
|
||||||
|
lineage
|
||||||
|
:rtype: :class:`datetime.datetime`"""
|
||||||
|
|
||||||
return self._notafterbefore(lambda x509: x509.get_notBefore(), version)
|
return self._notafterbefore(lambda x509: x509.get_notBefore(), version)
|
||||||
|
|
||||||
def notafter(self, version=None):
|
def notafter(self, version=None):
|
||||||
"""When is the ending validity time of the specified version of the
|
"""When does the specified cert version stop being valid?
|
||||||
cert in this lineage? (If no version is specified, use the current
|
|
||||||
version.)"""
|
(If no version is specified, use the current version.)
|
||||||
|
|
||||||
|
:param int version: the desired version number
|
||||||
|
|
||||||
|
:returns: the notAfter value from the specified cert version in this
|
||||||
|
lineage
|
||||||
|
:rtype: :class:`datetime.datetime`"""
|
||||||
|
|
||||||
return self._notafterbefore(lambda x509: x509.get_notAfter(), version)
|
return self._notafterbefore(lambda x509: x509.get_notAfter(), version)
|
||||||
|
|
||||||
def should_autodeploy(self):
|
def should_autodeploy(self):
|
||||||
"""Should this certificate lineage be updated automatically to
|
"""Should this lineage now automatically deploy a newer version?
|
||||||
point to an existing pending newer version? (Considers whether
|
|
||||||
autodeployment is enabled, whether a relevant newer version
|
This is a policy question and does not only depend on whether there
|
||||||
exists, and whether the time interval for autodeployment has
|
is a newer version of the cert. (This considers whether autodeployment
|
||||||
been reached.)"""
|
is enabled, whether a relevant newer version exists, and whether the
|
||||||
|
time interval for autodeployment has been reached.)
|
||||||
|
|
||||||
|
:returns: whether the lineage now ought to autodeploy an existing
|
||||||
|
newer cert version
|
||||||
|
:rtype: bool"""
|
||||||
|
|
||||||
if ("autodeploy" not in self.configuration or
|
if ("autodeploy" not in self.configuration or
|
||||||
self.configuration.as_bool("autodeploy")):
|
self.configuration.as_bool("autodeploy")):
|
||||||
if self.has_pending_deployment():
|
if self.has_pending_deployment():
|
||||||
@@ -287,18 +426,36 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
def ocsp_revoked(self, version=None):
|
def ocsp_revoked(self, version=None):
|
||||||
# pylint: disable=no-self-use,unused-argument
|
# pylint: disable=no-self-use,unused-argument
|
||||||
"""Is the specified version of this certificate lineage revoked
|
"""Is the specified cert version revoked according to OCSP?
|
||||||
according to OCSP or intended to be revoked according to Let's
|
|
||||||
Encrypt OCSP extensions? (If no version is specified, use the
|
Also returns True if the cert version is declared as intended to be
|
||||||
current version.)"""
|
revoked according to Let's Encrypt OCSP extensions. (If no version
|
||||||
|
is specified, uses the current version.)
|
||||||
|
|
||||||
|
This method is not yet implemented and currently always returns False.
|
||||||
|
|
||||||
|
:param int version: the desired version number
|
||||||
|
|
||||||
|
:returns: whether the certificate is or will be revoked
|
||||||
|
:rtype: bool"""
|
||||||
|
|
||||||
# XXX: This query and its associated network service aren't
|
# XXX: This query and its associated network service aren't
|
||||||
# implemented yet, so we currently return False (indicating that the
|
# implemented yet, so we currently return False (indicating that the
|
||||||
# certificate is not revoked).
|
# certificate is not revoked).
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def should_autorenew(self):
|
def should_autorenew(self):
|
||||||
"""Should an attempt be made to automatically renew the most
|
"""Should we now try to autorenew the most recent the most cert version?
|
||||||
recent certificate in this certificate lineage right now?"""
|
|
||||||
|
This is a policy question and does not only depend on whether the
|
||||||
|
cert is expired. (This considers whether autorenewal is enabled,
|
||||||
|
whether the cert is revoked, and whether the time interval for
|
||||||
|
autorenewal has been reached.)
|
||||||
|
|
||||||
|
:returns: whether an attempt should now be made to autorenew the
|
||||||
|
most current cert version in this lineage
|
||||||
|
:rtype: bool"""
|
||||||
|
|
||||||
if ("autorenew" not in self.configuration
|
if ("autorenew" not in self.configuration
|
||||||
or self.configuration.as_bool("autorenew")):
|
or self.configuration.as_bool("autorenew")):
|
||||||
# Consider whether to attempt to autorenew this cert now
|
# Consider whether to attempt to autorenew this cert now
|
||||||
@@ -324,16 +481,35 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
|||||||
def new_lineage(cls, lineagename, cert, privkey, chain,
|
def new_lineage(cls, lineagename, cert, privkey, chain,
|
||||||
renewalparams=None, config=DEFAULTS):
|
renewalparams=None, config=DEFAULTS):
|
||||||
# pylint: disable=too-many-locals,too-many-arguments
|
# pylint: disable=too-many-locals,too-many-arguments
|
||||||
"""Create a new certificate lineage with the (suggested) lineage name
|
"""Create a new certificate lineage.
|
||||||
lineagename, and the associated cert, privkey, and chain (the
|
|
||||||
associated fullchain will be created automatically). Optional
|
Attempts to create a certificate lineage -- enrolled for potential
|
||||||
configurator and renewalparams record the configuration that was
|
future renewal -- with the (suggested) lineage name lineagename,
|
||||||
originally used to obtain this cert, so that it can be reused later
|
and the associated cert, privkey, and chain (the associated
|
||||||
during automated renewal.
|
fullchain will be created automatically). Optional configurator
|
||||||
|
and renewalparams record the configuration that was originally
|
||||||
|
used to obtain this cert, so that it can be reused later during
|
||||||
|
automated renewal.
|
||||||
|
|
||||||
Returns a new RenewableCert object referring to the created
|
Returns a new RenewableCert object referring to the created
|
||||||
lineage. (The actual lineage name, as well as all the relevant
|
lineage. (The actual lineage name, as well as all the relevant
|
||||||
file paths, will be available within this object.)"""
|
file paths, will be available within this object.)
|
||||||
|
|
||||||
|
:param str lineagename: the suggested name for this lineage
|
||||||
|
(normally the current cert's first subject DNS name)
|
||||||
|
:param str cert: the initial certificate version in PEM format
|
||||||
|
:param str privkey: the private key in PEM format
|
||||||
|
:param str chain: the certificate chain in PEM format
|
||||||
|
:param :class:`configobj.ConfigObj` renewalparams: parameters that
|
||||||
|
should be used when instantiating authenticator and installer
|
||||||
|
objects in the future to attempt to renew this cert or deploy
|
||||||
|
new versions of it
|
||||||
|
:param :class:`configobj.ConfigObj` config: renewal configuration
|
||||||
|
defaults, affecting, for example, the locations of the
|
||||||
|
directories where the associated files will be saved
|
||||||
|
|
||||||
|
:returns: the newly-created RenewalCert object
|
||||||
|
:rtype: :class:`storage.renewableCert`"""
|
||||||
|
|
||||||
# Examine the configuration and find the new lineage's name
|
# Examine the configuration and find the new lineage's name
|
||||||
configs_dir = config["renewal_configs_dir"]
|
configs_dir = config["renewal_configs_dir"]
|
||||||
@@ -394,9 +570,23 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
|
|
||||||
def save_successor(self, prior_version, new_cert, new_privkey, new_chain):
|
def save_successor(self, prior_version, new_cert, new_privkey, new_chain):
|
||||||
"""Save a new cert and chain as a successor of a specific prior
|
"""Save new cert and chain as a successor of a prior version.
|
||||||
version in this lineage. Returns the new version number that was
|
|
||||||
created. Note: does NOT update links to deploy this version."""
|
Returns the new version number that was created. Note: does NOT
|
||||||
|
update links to deploy this version.
|
||||||
|
|
||||||
|
:param int prior_version: the old version to which this version is
|
||||||
|
regarded as a successor (used to choose a privkey, if the key
|
||||||
|
has not changed, but otherwise this information is not permanently
|
||||||
|
recorded anywhere)
|
||||||
|
:param str new_cert: the new certificate, in PEM format
|
||||||
|
:param str new_privkey: the new private key, in PEM format, or None,
|
||||||
|
if the private key has not changed
|
||||||
|
:param str new_chain: the new chain, in PEM format
|
||||||
|
|
||||||
|
:returns: the new version number that was created
|
||||||
|
:rtype: int"""
|
||||||
|
|
||||||
# XXX: assumes official archive location rather than examining links
|
# XXX: assumes official archive location rather than examining links
|
||||||
# XXX: consider using os.open for availablity of os.O_EXCL
|
# XXX: consider using os.open for availablity of os.O_EXCL
|
||||||
# XXX: ensure file permissions are correct; also create directories
|
# XXX: ensure file permissions are correct; also create directories
|
||||||
|
|||||||
Reference in New Issue
Block a user