Skip to content

Certificate.set_certificate_for_service limiting possible services, not allowing reverse proxy services #341

@oldShatteredHands7

Description

@oldShatteredHands7

Background
My use-case is to regularly check my existing certificates and renew them through step-ca if necessary.
As I am unable to use acme.sh, I'm doing it in my own script, wanting to utilize your library.

Workflow

  1. Create a new certificate and save its id
  2. Use cert id from step 1 and service id to call Certificate.set_certificate_for_service

Issue
For reasons unknown to me, the current code is very restrictive and will produce a Key Error if the service name is not in servicedatadict / servicedatadictdsm7. Or in other words, whenever it is not "DSM Desktop Service".

...
servicedatadict = {
            "DSM Desktop Service": {
                "display_name": "DSM Desktop Service",
                "display_name_i18n": "common:web_desktop",
                "isPkg": False,
                "owner": "root",
                "service": "default",
                "subscriber": "system",
            }
        }

        # needed for DSM7
        servicedatadictdsm7 = {
            "DSM Desktop Service": {
                "multiple_cert": True,
                "user_setable": True
            }
        }

        # construct the payload
        payloaddict = {
            "settings": json.dumps([{
                "service": {**servicedatadict[service_name],
                            **(servicedatadictdsm7[service_name] if (self.session._version == 7) else {})},
                "old_id": f"{old_certid}",
                "id": f"{cert_id}"
            }], separators=(',', ':')),
            "api": f"{api_name}",
            "version": f"{info['minVersion']}",
            "method": "set"
        }
...

Maybe it's a misunderstanding on my side, but I have multiple others services, especially reverse proxies, that I would like to update this way, so my first assumption would be that we could - assuming that every service is always assigned to a cert by default - grab the targetServiceDefinition from the already existing loop.

...
        targetServiceDefinition = {}
        for cert in certs:
            for service in cert['services']:
                # look for the previous cert
                if service['display_name'] == service_name:
                    # check every certificate if it does contain the given service
                    old_certid = cert['id']
                    # since we do not want to rely on a separate call to retreive all services, 
                    # we utilize this mechanism to get a hold of the targeted service
                    targetServiceDefinition = {
                        service_name: service
                    }
                    break
...

When creating the payload, we could do it in a safe way and fall back to taking the service definition from targetServiceDefinition if it is not in either servicedatadict or servicedatadictdsm7 (in case of DSM 7)

...
        # first try to retrieve service def. from servicedatadict OR servicedatadictdsm7 in case of DSM7
        dsm_service_ref = servicedatadict.get(service_name, {})
        if self.session._version == 7:
            dsm_service_ref = {
                **dsm_service_ref,
                **servicedatadictdsm7.get(service_name, {})
            }
        # if unsuccesful, try to use targetServiceDefinition instead
        payload_service_def = (
            targetServiceDefinition.get(service_name, {})
            if not dsm_service_ref
            else dsm_service_ref
        )
...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions