diff --git a/Makefile b/Makefile index 36d5863543..c623ed9b3d 100644 --- a/Makefile +++ b/Makefile @@ -6,13 +6,16 @@ pyresttest=venv/bin/pyresttest mypy=venv/bin/mypy manage=$(python) $(CURDIR)/manage.py +.PHONY: lint lint: $(pycodestyle) $(CURDIR)/nextcloudappstore --exclude=migrations $(mypy) --silent-imports --disallow-untyped-defs $(CURDIR)/nextcloudappstore/core/api/v1/release +.PHONY: test test: lint $(manage) test --settings nextcloudappstore.settings.development +.PHONY: resetup resetup: rm -f db.sqlite3 $(manage) migrate --settings nextcloudappstore.settings.development @@ -20,11 +23,13 @@ resetup: @echo "from django.contrib.auth.models import User; from allauth.account.models import EmailAddress; EmailAddress.objects.create(user=User.objects.get(username='admin'), email='admin@example.com', verified=True, primary=True)" | $(manage) shell --settings nextcloudappstore.settings.development $(manage) loaddata $(CURDIR)/nextcloudappstore/**/fixtures/*.json --settings nextcloudappstore.settings.development +.PHONY: initmigrations initmigrations: rm -f $(CURDIR)/nextcloudappstore/**/migrations/0*.py $(manage) makemigrations --settings nextcloudappstore.settings.development # Only for local setup, do not use in production +.PHONY: dev-setup dev-setup: pyvenv venv $(pip) install -r $(CURDIR)/requirements/development.txt @@ -43,3 +48,8 @@ dev-setup: $(manage) loaddata $(CURDIR)/nextcloudappstore/**/fixtures/*.json --settings nextcloudappstore.settings.development @echo "from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'admin@example.com', 'admin')" | $(manage) shell --settings nextcloudappstore.settings.development @echo "from django.contrib.auth.models import User; from allauth.account.models import EmailAddress; EmailAddress.objects.create(user=User.objects.get(username='admin'), email='admin@example.com', verified=True, primary=True)" | $(manage) shell --settings nextcloudappstore.settings.development + +.PHONY: docs +docs: + @echo "hi" + $(MAKE) -C $(CURDIR)/docs/ html diff --git a/docs/developer.rst b/docs/developer.rst index 8a2079d2da..74556ddfff 100644 --- a/docs/developer.rst +++ b/docs/developer.rst @@ -3,7 +3,7 @@ App Developer Guide Most of today's developers publish their source code on GitHub, BitBucket or on their own GitLab instance. These tools typically also provide a way to release new versions based on Git tags or by uploading custom archives. -Advanced users and developers typically prefer to download the app directly from these services whereas administrators or novice users look for app releases on the app store. This means that you have to take care of publishing two releases on two different platforms. +Advanced users and developers typically prefer to download the app directly from these services whereas administrators or novice users look for app releases on the App Store. This means that you have to take care of publishing two releases on two different platforms. We want to avoid duplication and make it harder to ship broken releases by mistake, therefore we went for the following solution: @@ -15,25 +15,113 @@ We want to avoid duplication and make it harder to ship broken releases by mista This keeps your repository up to date and satisfies the needs of developers and advanced users. -App Release Workflow --------------------- +Publishing Apps on the App Store +-------------------------------- +Hosting the archive on a different host means of course that we can not guarantee that the contents have not been tampered with. Neither can we guarantee that the actual app developer uploaded the app. Therefore we require you to sign your app using a certificate. -To publish an app release on the app store you simply send us a download link for the release archive using either :doc:`ncdev `, the `app upload web form `_, or any tool that can access the :doc:`restapi` (even with curl). We then do the following: +Obtaining a Certificate +~~~~~~~~~~~~~~~~~~~~~~~ +The certificates should be stored in **~/.nextcloud/certificates/** so first create the folder if it does not exist yet:: -* Your archive is downloaded from the given location. This ensures that your users don't hit dead links. If your archive is too big, we will abort the download. + mkdir -p ~/.nextcloud/certificates/ -* The archive is then extracted and the package structure is validated: +Then change into the directory:: - * The archive most only contain one top level folder consisting of lower case ASCII characters and underscores - * The archive must contain an **info.xml** file inside the **appinfo** directory which in turn is located in the top folder + cd ~/.nextcloud/certificates/ -* The app's metadata is then extracted from the **info.xml** file +and generate your private certificate and CSR:: -* The info.xml is reformatted using XSLT to bring everything into the correct order (required for XSD 1.0) and unknown elements are dropped + openssl req -nodes -newkey rsa:4096 -keyout APP_ID.key -out APP_ID.csr -subj "/CN=APP_ID" -* The cleaned up info.xml is then validated using an XML Schema (see :ref:`info-schema`) +Replace **APP_ID** with your app id, e.g. if your app had an id called **news** you would execute the following command:: -* The release is then either created or updated. The downloaded archive will be deleted + openssl req -nodes -newkey rsa:4096 -keyout news.key -out news.csr -subj "/CN=news" + +.. note:: Keep in mind that an app id must only contain lowercase ASCII characters and underscores! + +Then post the contents of your **APP_ID.csr** (e.g. **~/.nextcloud/certificates/news.csr**) on `on our issue tracker `_ and configure your GitHub account to show your mail address in your profile. + +Nextcloud might ask you for further information to verify that you’re the legitimate owner of the application. Make sure to keep the private key file (**APP_ID.key**, e.g. **~/.nextcloud/certificates/news.key**) secret and not disclose it to any third-parties. + +After we approved your certificate, we will post your signed public certificate as a response on your issue. Take the contents and store it in the same folder with the file name **APP_ID.crt** (e.g. **~/.nextcloud/certificates/news.crt**). Make sure to get rid of excess whitespace at the beginning and end of your file. Your public signed certificate's file contents should look similar to this:: + + -----BEGIN CERTIFICATE----- + MIID+TCCAeECAhAMMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNVBAYTAlVTMQ8wDQYD + VQQIDAZCb3N0b24xFjAUBgNVBAoMDW93bkNsb3VkIEluYy4xNTAzBgNVBAMMLG93 + bkNsb3VkIENvZGUgU2lnbmluZyBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MB4XDTE2 + MDcyNjEwMTIyOFoXDTI2MDcyNDEwMTIyOFowFzEVMBMGA1UEAwwMZm9sZGVycGxh + eWVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8BnaiY7+oPMmYalU + Cpv/U+36PUTQd3r9t73l7opUyv7F2yshrgKk9jdINOWZaPYxFi5mSnolu6KP/nNq + Bsh7HTHFo9xmVg2lia4WxmO23GBp94GEj4irYSP3FcrrT+aLBmr3sM2zxfIWJ9K/ + 9wC8rFhyQjMaQLqC48VRjz8eI6rRSAUrcY+B6GAB0O2XZifSYVgzwh3lV1Xno2uT + 69+V5HfXEEz8u5YRnoFBC8hfaRzGlnm0cUZrVEgEcCjt1pPf+HeGUnHafT8uUbET + 7Ys6QCQoaiKy7D7eiUh2kOOcChFAxiGX+9ahiIESZUrlDs8m8rmoa8C3fqho4C9g + nwEoowIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQAZts21nfQGzkPsiDseIZjg1Dh7 + KavuEjxJHqSbTlqi1W9CxievQF205IbfuRLsbsi1Kw1hFivse//nTkFiMvgdqKsM + zSzsUq24tjWFDpNVHgVoPCBG6t7yYP6PdWNZtPSt76w8l7fAo9Fm2tBlFvMfF4Pe + 3nveZjV5ns71oFpxLJobl25xj4Q63DKRoN0vVv6bEe+rbd6REPI+Ep8w43A8/wqc + pB0q6j3Fs4FRlNUqshLaRN2HVbllb/+hlA1REOBGEvAuSHzXrThCS2PpEY8Ds7IG + 0rSuEdzwCd3c+vk+pssgxmFHBDPDJUsKSgUCF5wzA4k42tK/sixSDJlPcVKZdRrY + +8XgaruPdIMoIVZHXdeNvBtra1kYRxZbeCpe1zSOiLL/xjSWVYEFhiO7ZBuHRDrq + gaJmQNZxzwEUrpLsN4QB4S3jVmCEZ9Rjp8hWuaShRBWwYjlfhKlRcdwCol/T7ODC + oioO3wBapwvsaCS4gmkmdBtvIKvbr62PM2nh6QpJwpyv9LPEXM5ZV0BT3AK8DIK6 + ThH5+uRF0QgDXHWIR55Gmh2usJ6VluPWT+f81Q3lH/jxXJfagGOFEFHtyT0yo23M + iazev6j9O2En+uDYLSWgQ7uN+cFYSdfjj1FRjsQ84e8CwNJ1nhiQ/HexMN8zwqDo + 6LboOQuGiCet+KggAg== + -----END CERTIFICATE----- + +.. note:: Be sure to follow the directory and naming structure for certificates. All our documentation examples and tools will assert this structure. + +Registering an App +~~~~~~~~~~~~~~~~~~ +After you've obtained your signed public certificate you can use it to register your app id on the App Store. To do that either use the :ref:`REST API ` or use the App Store's `register app web interface `_. + +The interface will ask you for the following things: + +* **Certificate**: Paste in the contents of your public certificate, e.g. **~/.nextcloud/certificates/news.crt** +* **Signature**: A signature over your app id to verify that you own the private certificate. Can be calculated by using the following command:: + + echo -n "APP_ID" | openssl dgst -sha512 -sign ~/.nextcloud/certificates/APP_ID.key | openssl base64 + + where **APP_ID** is your app's id, e.g:: + + echo -n "news" | openssl dgst -sha512 -sign ~/.nextcloud/certificates/news.key | openssl base64 + +We will then verify the certificate and signature and register you as the app's owner. You are now able to publish releases. + +Uploading an App Release +~~~~~~~~~~~~~~~~~~~~~~~~ +After you've registered your app you can upload your app's releases to the App Store. To do that either use the :ref:`REST API ` or use the App Store's `upload app release web interface `_. + +The interface will ask you for the following things: + +* **Download**: A download link to your app release archive (tar.gz) +* **Nightly**: Check if you are uploading a nightly release +* **Signature**: A signature over your release archive. Can be calculated by using the following command:: + + openssl dgst -sha512 -sign ~/.nextcloud/certificates/APP_ID.key /path/to/app.tar.gz | openssl base64 + + where **APP_ID** is your app's id, e.g:: + + openssl dgst -sha512 -sign ~/.nextcloud/certificates/news.key /path/to/news.tar.gz | openssl base64 + +We then download the archive and verify the signature. In addition we try to verify and use as much information as possible form the archive, e.g.: + +* The archive most only contain one top level folder consisting of lower case ASCII characters and underscores + +* The archive must contain an **info.xml** file inside the **appinfo** directory which in turn is located in the top folder + +* The info.xml is reformatted using XSLT to bring everything into the correct order (required for XSD 1.0) and unknown elements are dropped. Old elements are migrated to their new equivalents if possible. Afterwards we validate it using an XML Schema (see :ref:`info-schema`) + +If everything went well the release is then either created or updated. The downloaded archive will be deleted from our server. + +Revoking a Certificate +~~~~~~~~~~~~~~~~~~~~~~ +If you've lost or leaked your private certificate you want to revoke your certificate. + +You can revoke your previous certificate by either posting your public certificate and revocation request `on our issue tracker `_ or by requesting a new certificate for an already requested app id. + +After you've obtained a new certificate, simply use it to register your app id again (only owners are allowed to do this). This will delete all previous releases from our server since their signature has become invalid. .. _app-metadata: @@ -175,7 +263,7 @@ author * can occur multiple times with different authors * can contain a **mail** attribute which must be an email * can contain a **homepage** which must be an URL - * will not (yet) be rendered on the app store + * will not (yet) be rendered on the App Store * will be provided through the REST API documentation/user * optional @@ -337,12 +425,3 @@ Various IDEs automatically validate and auto complete XML elements and attribute -Verification ------------- -Since we don't host the package ourselves this implies that the download location must be trusted. The following mechanisms are in place to guarantee that the downloaded version has not been tampered with: - -* You can submit a sha256sum hash in addition to the download link. The hash is validated on the user's server when he installs it. If you omit the hash, we generate it from the downloaded archive - -* You can sign your code `using a certificate `_ - -* You must supply an HTTPS download url for the archive (tar.gz only) diff --git a/docs/ncdev.rst b/docs/ncdev.rst index cc83f71a70..1f01e32018 100644 --- a/docs/ncdev.rst +++ b/docs/ncdev.rst @@ -1,13 +1,15 @@ ncdev Integration ================= +.. note:: ncdev is still work in progress, this is a specification of how it should work + `ncdev `_ implements the :doc:`app store REST api ` and allows you to easily manage your apps through your CLI. Configuration ------------- -ncdev's configuration is store inside ~/.ncdevrc and the following settings are available for the app store: +ncdev's configuration is store inside **~/.ncdevrc** and the following settings are available for the app store: .. code-block:: ini @@ -22,37 +24,49 @@ ncdev's configuration is store inside ~/.ncdevrc and the following settings are * **token**: Your app store token if you don't want to add user and password. If all are present, user and password will be ignored. * **url**: Url to the app store +Furthermore ncdev expects your app certificates to be present in **~/.nextcloud/certificates/APP_ID.key** and ****~/.nextcloud/certificates/APP_ID.crt** where **APP_ID** is your app's id (same as your app folder). + Using ncdev ----------- The following commands are available: +* :ref:`ncdev-register-app` + * :ref:`ncdev-upload-release` * :ref:`ncdev-delete-release` * :ref:`ncdev-delete-app` +.. _ncdev-register-app: + +Register a New App +~~~~~~~~~~~~~~~~~~ +To register a new app use:: + + ncdev appstore register APP_ID + +where **APP_ID** is the app's id that you want to register. + +.. note:: Certificates need to be in place + +.. note:: Registering an already present app id with a new certificate will delete all its existing releases! + .. _ncdev-upload-release: Upload a New Release ~~~~~~~~~~~~~~~~~~~~ To upload a new release use:: - ncdev appstore release https://github.com/nextcloud/news/archive/8.8.0.tar.gz --checksum 65e613318107bceb131af5cf8b71e773b79e1a9476506f502c8e2017b52aba15 + ncdev appstore release https://github.com/nextcloud/news/archive/8.8.0.tar.gz -where the link is the url to your app release archive. Checksum is an optional parameter and can be computed by using:: +where the link is the url to your app release archive. Ncdev will first download and create the app signature, then submit the link including the signature. If the release exists already it will be overwritten. You can omit that step by explicitly providing a signature:: - sha256sum 8.8.0.tar.gz - -If you omit the checksum it will be computed for you. - -The first time you upload an app you will be registered as app owner for the app's id. - -If the release exists already it will be overwritten. + ncdev appstore release https://github.com/nextcloud/news/archive/8.8.0.tar.gz --signature THE_SIGNATURE To upload a **nightly** release use:: - ncdev appstore release https://github.com/nextcloud/news/archive/8.8.0.tar.gz --nightly --checksum 65e613318107bceb131af5cf8b71e773b79e1a9476506f502c8e2017b52aba15 + ncdev appstore release https://github.com/nextcloud/news/archive/8.8.0.tar.gz --nightly .. _ncdev-delete-app: diff --git a/docs/restapi.rst b/docs/restapi.rst index 5b01e38a8f..53e7ba8060 100644 --- a/docs/restapi.rst +++ b/docs/restapi.rst @@ -18,6 +18,8 @@ Several routes require authentication. The following authentication methods are Authorization: Token TOKEN +.. note:: If you created your account using GitHub you will always need to use token authentication since we do not have access to your password. The token can be looked up in `your account settings `_ + Specification ------------- @@ -31,6 +33,8 @@ The following API routes are present: * :ref:`api-all-releases` +* :ref:`api-register-app` + * :ref:`api-create-release` * :ref:`api-delete-release` @@ -360,6 +364,55 @@ featured categories The string value is the category's id attribute, see :ref:`api-all-categories` + + +.. _api-register-app: + +Register a New App +~~~~~~~~~~~~~~~~~~ +Before you can upload release you first need to register its app id. To do that use: + +* **Url**: POST /api/v1/apps + +* **Authentication** Basic, Token + +* **Content-Type**: application/json + +* **Request body**: + + * **certificate**: Your public certificate whose CN is equal to the app id, should be stored in **~/.nextcloud/certificates/APP_ID.cert** where **APP_ID** is your app's id + * **signature**: A SHA512 signature over the app id using the app's certificate, can be created using:: + + echo -n "APP_ID" | openssl dgst -sha512 -sign ~/.nextcloud/certificates/APP_ID.key | openssl base64 + + .. code-block:: json + + { + "certificate": "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEojCCA4qgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwezELMAkGA1UEBhMCREUx\r\nGzAZBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzEXMBUGA1UECgwOTmV4dGNsb3Vk\r\nIEdtYkgxNjA0BgNVBAMMLU5leHRjbG91ZCBDb2RlIFNpZ25pbmcgSW50ZXJtZWRp\r\nYXRlIEF1dGhvcml0eTAeFw0xNjA2MTIyMTA1MDZaFw00MTA2MDYyMTA1MDZaMGYx\r\nCzAJBgNVBAYTAkRFMRswGQYDVQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxEjAQBgNV\r\nBAcMCVN0dXR0Z2FydDEXMBUGA1UECgwOTmV4dGNsb3VkIEdtYkgxDTALBgNVBAMM\r\nBGNvcmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUxcrn2DC892IX\r\n8+dJjZVh9YeHF65n2ha886oeAizOuHBdWBfzqt+GoUYTOjqZF93HZMcwy0P+xyCf\r\nQqak5Ke9dybN06RXUuGP45k9UYBp03qzlUzCDalrkj+Jd30LqcSC1sjRTsfuhc+u\r\nvH1IBuBnf7SMUJUcoEffbmmpAPlEcLHxlUGlGnz0q1e8UFzjbEFj3JucMO4ys35F\r\nqZS4dhvCngQhRW3DaMlQLXEUL9k3kFV+BzlkPzVZEtSmk4HJujFCnZj1vMcjQBg\/\r\nBqq1HCmUB6tulnGcxUzt\/Z\/oSIgnuGyENeke077W3EyryINL7EIyD4Xp7sxLizTM\r\nFCFCjjH1AgMBAAGjggFDMIIBPzAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIG\r\nQDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgU2VydmVyIENlcnRp\r\nZmljYXRlMB0GA1UdDgQWBBQwc1H9AL8pRlW2e5SLCfPPqtqc0DCBpQYDVR0jBIGd\r\nMIGagBRt6m6qqTcsPIktFz79Ru7DnnjtdKF+pHwwejELMAkGA1UEBhMCREUxGzAZ\r\nBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzESMBAGA1UEBwwJU3R1dHRnYXJ0MRcw\r\nFQYDVQQKDA5OZXh0Y2xvdWQgR21iSDEhMB8GA1UEAwwYTmV4dGNsb3VkIFJvb3Qg\r\nQXV0aG9yaXR5ggIQADAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUH\r\nAwEwDQYJKoZIhvcNAQELBQADggEBADZ6+HV\/+0NEH3nahTBFxO6nKyR\/VWigACH0\r\nnaV0ecTcoQwDjKDNNFr+4S1WlHdwITlnNabC7v9rZ\/6QvbkrOTuO9fOR6azp1EwW\r\n2pixWqj0Sb9\/dSIVRpSq+jpBE6JAiX44dSR7zoBxRB8DgVO2Afy0s80xEpr5JAzb\r\nNYuPS7M5UHdAv2dr16fDcDIvn+vk92KpNh1NTeZFjBbRVQ9DXrgkRGW34TK8uSLI\r\nYG6jnfJ6eJgTaO431ywWPXNg1mUMaT\/+QBOgB299QVCKQU+lcZWptQt+RdsJUm46\r\nNY\/nARy4Oi4uOe88SuWITj9KhrFmEvrUlgM8FvoXA1ldrR7KiEg=\r\n-----END CERTIFICATE-----", + "signature": "65e613318107bceb131af5cf8b71e773b79e1a9476506f502c8e2017b52aba15" + } + + +* **Example CURL request**:: + + curl -X POST -u "user:password" https://apps.nextcloud.com/api/v1/apps -H "Content-Type: application/json" -d '{"certificate": "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEojCCA4qgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwezELMAkGA1UEBhMCREUx\r\nGzAZBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzEXMBUGA1UECgwOTmV4dGNsb3Vk\r\nIEdtYkgxNjA0BgNVBAMMLU5leHRjbG91ZCBDb2RlIFNpZ25pbmcgSW50ZXJtZWRp\r\nYXRlIEF1dGhvcml0eTAeFw0xNjA2MTIyMTA1MDZaFw00MTA2MDYyMTA1MDZaMGYx\r\nCzAJBgNVBAYTAkRFMRswGQYDVQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxEjAQBgNV\r\nBAcMCVN0dXR0Z2FydDEXMBUGA1UECgwOTmV4dGNsb3VkIEdtYkgxDTALBgNVBAMM\r\nBGNvcmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUxcrn2DC892IX\r\n8+dJjZVh9YeHF65n2ha886oeAizOuHBdWBfzqt+GoUYTOjqZF93HZMcwy0P+xyCf\r\nQqak5Ke9dybN06RXUuGP45k9UYBp03qzlUzCDalrkj+Jd30LqcSC1sjRTsfuhc+u\r\nvH1IBuBnf7SMUJUcoEffbmmpAPlEcLHxlUGlGnz0q1e8UFzjbEFj3JucMO4ys35F\r\nqZS4dhvCngQhRW3DaMlQLXEUL9k3kFV+BzlkPzVZEtSmk4HJujFCnZj1vMcjQBg\/\r\nBqq1HCmUB6tulnGcxUzt\/Z\/oSIgnuGyENeke077W3EyryINL7EIyD4Xp7sxLizTM\r\nFCFCjjH1AgMBAAGjggFDMIIBPzAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIG\r\nQDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgU2VydmVyIENlcnRp\r\nZmljYXRlMB0GA1UdDgQWBBQwc1H9AL8pRlW2e5SLCfPPqtqc0DCBpQYDVR0jBIGd\r\nMIGagBRt6m6qqTcsPIktFz79Ru7DnnjtdKF+pHwwejELMAkGA1UEBhMCREUxGzAZ\r\nBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzESMBAGA1UEBwwJU3R1dHRnYXJ0MRcw\r\nFQYDVQQKDA5OZXh0Y2xvdWQgR21iSDEhMB8GA1UEAwwYTmV4dGNsb3VkIFJvb3Qg\r\nQXV0aG9yaXR5ggIQADAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUH\r\nAwEwDQYJKoZIhvcNAQELBQADggEBADZ6+HV\/+0NEH3nahTBFxO6nKyR\/VWigACH0\r\nnaV0ecTcoQwDjKDNNFr+4S1WlHdwITlnNabC7v9rZ\/6QvbkrOTuO9fOR6azp1EwW\r\n2pixWqj0Sb9\/dSIVRpSq+jpBE6JAiX44dSR7zoBxRB8DgVO2Afy0s80xEpr5JAzb\r\nNYuPS7M5UHdAv2dr16fDcDIvn+vk92KpNh1NTeZFjBbRVQ9DXrgkRGW34TK8uSLI\r\nYG6jnfJ6eJgTaO431ywWPXNg1mUMaT\/+QBOgB299QVCKQU+lcZWptQt+RdsJUm46\r\nNY\/nARy4Oi4uOe88SuWITj9KhrFmEvrUlgM8FvoXA1ldrR7KiEg=\r\n-----END CERTIFICATE-----","signature": "65e613318107bceb131af5cf8b71e773b79e1a9476506f502c8e2017b52aba15"}' + +* **Returns**: + + * **HTTP 200**: If the app's certificate was updated successfully and all its releases have been deleted + * **HTTP 201**: If the app id was registered successfully + * **HTTP 400**: If the app id contains invalid characters, the signature could not be validated or if the posted app certificate has been revoked + * **HTTP 401**: If the user is not authenticated + * **HTTP 403**: If the user is not authorized to update the app signature (only owners are allowed to do so) + +You can also use this route to register a new certificate for an app if you are the app owner. However keep in mind that this will delete all previous app releases, since their signatures are now invalid and not installable anymore. + +Find out more how to generate and request the certificate signature by following the :doc:`developer`. + +.. note:: **DO NOT** post your private key which is stored in the **.key** file. The private certificate needs to be stored securely. If you are unsure whether a file is a private certificate or the public one: your private certificate's content starts with **-----BEGIN PRIVATE KEY-----**, whereas your public certificate's content starts with **-----BEGIN CERTIFICATE-----** + +.. note:: Keep in mind that we verify that the posted certificate and the signature are valid: the certificate needs to be signed by us and your app id signature must stem from the same certificate and match the expected result. + .. _api-create-release: Publish a New App Release @@ -377,12 +430,10 @@ The following request will create a new app release or update an existing releas * **download**: An Https (Http is not allowed!) link to the archive packaged (maximum size: 20 Megabytes) as tar.gz, info.xml must be smaller than 512Kb * **signature**: A SHA512 signature over the archive using the app's certificate, can be created using:: - openssl dgst -sha512 -sign /path/to/private-cert.key /path/to/app.tar.gz | openssl base64 + openssl dgst -sha512 -sign ~/.nextcloud/certificates/APP_ID.key /path/to/app.tar.gz | openssl base64 * **nightly (Optional)**: If true this release will be stored as a nightly. All previous nightly releases will be deleted. - sha256sum release.tar.gz - .. code-block:: json { @@ -394,17 +445,17 @@ The following request will create a new app release or update an existing releas * **Example CURL request**:: - curl -X POST -u "user:password" https://apps.nextcloud.com/api/v1/apps/releases -H "Content-Type: application/json" -d '{"download":"https://example.com/release.tar.gz"}' + curl -X POST -u "user:password" https://apps.nextcloud.com/api/v1/apps/releases -H "Content-Type: application/json" -d '{"download":"https://example.com/release.tar.gz", "signature": "65e613318107bceb131af5cf8b71e773b79e1a9476506f502c8e2017b52aba15"}' * **Returns**: * **HTTP 200**: If the app release was update successfully * **HTTP 201**: If the app release was created successfully - * **HTTP 400**: If the app contains invalid data, is too large or could not be downloaded + * **HTTP 400**: If the app release contains invalid data, is too large, is not registered yet, the signature could not be validated, the current app certificate has been revoked or could not be downloaded from the provided link * **HTTP 401**: If the user is not authenticated * **HTTP 403**: If the user is not authorized to create or update the app release -If there is no app with the given app id yet, a new app is created and the owner is set in to the logged in user. Then the **info.xml** file which lies in the compressed archive's folder **app-id/appinfo/info.xml** is being parsed and validated. The validated result is then saved in the database. Both owners and co-maintainers are allowed to upload new releases. +If there is no app with the given app id yet it will fail: you need to :ref:`register your app id first `. Then the **info.xml** file which lies in the compressed archive's folder **app-id/appinfo/info.xml** is being parsed and validated. Afterwards the provided signature will be validated using the app's certificate and the downloaded archive's SHA512 checksum. The validated result is then saved in the database. Both owners and co-maintainers are allowed to upload new releases. If the app release version is the latest version, everything is updated. If it's not the latest release, only release relevant details are updated. This **excludes** the following info.xml elements: diff --git a/nextcloudappstore/core/forms.py b/nextcloudappstore/core/forms.py index 1ca4f86efc..dc2c9dd7cd 100644 --- a/nextcloudappstore/core/forms.py +++ b/nextcloudappstore/core/forms.py @@ -13,15 +13,32 @@ RATING_CHOICES = ( class AppReleaseUploadForm(Form): download = CharField(label=_('Download link (tar.gz)'), max_length=256) - signature = CharField(widget=Textarea, label=_('SHA512 signature'), - help_text=_( - 'Hint: can be calculated by executing the ' - 'following command: openssl dgst -sha512 -sign ' - '/path/to/private-cert.key /path/to/app.tar.gz ' - '| openssl base64')) + signature = CharField( + widget=Textarea, + label=_('SHA512 signature'), + help_text=_( + 'Hint: can be calculated by executing the ' + 'following command: openssl dgst -sha512 -sign ' + '~/.nextcloud/certificates/APP_ID.key ' + '/path/to/app.tar.gz | openssl base64')) nightly = BooleanField(label=_('Nightly')) +class AppRegisterForm(Form): + certificate = CharField( + widget=Textarea(attrs={'pattern': '-----BEGIN CERTIFICATE-----.*'}), + label=_('Public certificate'), + help_text=_( + 'Usually stored in ~/.nextcloud/certificates/APP_ID.crt')) + signature = CharField( + widget=Textarea, + label=_('SHA512 signature'), + help_text=_( + 'Hint: can be calculated by executing the ' + 'following command: echo -n "APP_ID" | openssl dgst -sha512 -sign ' + '~/.nextcloud/certificates/APP_ID.key | openssl base64')) + + class AppRatingForm(Form): def __init__(self, *args, **kwargs): self._id = kwargs.pop('id', None)