Skip to main content

CDN Apps

ArvanCloud Marketplace is a platform that includes hundreds of applications and cloud software that allows you to quickly find the product you need and install it with one click.

You can easily launch the program you need in the cloud environment and place it on your service platform in ArvanCloud Marketplace. All settings for installation and usage are included in each program by default. Also, by installing Marketplace applications, you no longer need to plan for the optimization and development of your software. ArvanCloud's cloud technology partners will automatically update your services by continuously updating existing software products.

In this guide, we will examine the structure and development of CDN applications for ArvanCloud marketplace.

To register a new program, a file called install.json must be created, which contains the JS and CSS content of the program (resources), parameters that can be received from the user during installation (options), and webhooks designated to call the API defined by the application developer when certain events occur.

In the following, you can see an example of the install.json file (without a hook).

{
"resources": {
"head": [
{
"type": "style",
"content": "#unique-app-prefix-style{background-color:#C1272D;text-align:center}"
},
{
"type": "script",
"content": "!function(){console.log('The application source code lies here, within an IIFE to prevent scope collision with other applications, also the app can access user defined options like this :' + INSTALL_OPTIONS.full_name)}();"
}
],
"body": [
{
"type": "script",
"content": "!function(){console.log('The application source code lies here, within an IIFE to prevent scope collision with other applications, also the app can access user defined options like this :' + INSTALL_OPTIONS.age)}();"
}
]
},
"options": {
"properties": {
"fullname": {
"title": "Full Name",
"description": "Enter Your FullName here, this is a string input",
"type": "string"
},
"age": {
"title": "age",
"description": "Enter Your age, this is a number input",
"type": "number"
},
"agreement": {
"title": "agreement",
"description": "Do you agree with our terms? this is a boolean input",
"type": "boolean"
}
},
"required": [
"fullname",
"age"
]
}
}

Resources

They include three items, head, body, and options_translations:

  • head

    They are added to the end of the <head> tag and before closing it in the user's website in the order defined in this file.

  • body

    They are added to the end of the <body> tag and before closing it in the user's website in the order defined in this file.

  • options_translations

    It is used for translation operations (supporting different languages).

  • type

    It can be one of two values "style" or "script".

  • content

    Corresponding to the defined type, it can contain js or CSS code. It should be kept in mind that the code must be minified and as small as possible. In appendix number one, we discuss the details and instructions for making each one

Options

The option provides the ability to personalize the application for each user. The option uses the JSON-Schema standard to define and validate values.

{
"options": {
"properties": {
"<option name>": {
"title": "shown to user during app installation",
"Description": "shown to user during app installation",
"default": "default value",
"type": "string" }
},
"required": [ //if the option is required include it in this array
"<option name>"
]
}
}

Appendix

Application Script Conversion Guide
  • As mentioned in the example, the program script must be placed inside an IIFE or Immediately Invoked Function Expression function so that the scope of the program is separate from the rest of the program.

  • All the options are accessible when running the script inside an object named INSTALL_OPTIONS. For example, if an option is defined as a token, its value can be retrieved as follows:

    INSTALL_OPTIONS.token
  • All double quotes must be escaped.

  • To skip double quotes and minify, you can get help from the CyberChef-Minify site.

  • Now you can put the output, which is a string, into the content of the install.json file.

Program Style Conversion Guide

It is enough to minify and escape the desired CSS without including the HTML tags. At this stage, you can also get help from the CyberChef-Minify site.

Hooks

A hook is a tool that allows developers to be notified of various events during the installation of the program and receive the necessary information that we will discuss further. It can also change the options set by the user or the schema (coming soon).

Consider an example of the following sample program:

{
"resources": {
"body": [
{
"type": "script",
"content": "!function(){console.log('Your favorite color is :' + INSTALL_OPTIONS.color + 'also you are registered on our website with help of hooks, your token is :' INSTALL_OPTIONS.token )}();"
}
]
},
"options": {
"properties": {
"color": {
"title": "desired color",
"description": "tell us what's your favorite color",
"type": "string"
},
"token": {
"title": "token by hook",
"description": "The token will be automatically generated for you, we register you as our customer with your arvan's email address",
"type": "string"
}
},
"required": [
"color",
"token"
]
},
"hooks": [
{
"endpoint": "https://example-vendor.com/hook",
"events": [
"before-new-install"
]
}
]
}

After being installed, in the browser console, this program prints the website owner's favorite color and token.

When installing the application, the user must fill in two mandatory fields. One color and another token. There is no problem to fill the color, but there are steps to be taken to get the token. The owner of the program needs to perform the registration process* at the moment for the convenience of the user and assign a token to the user to be placed in the relevant field.

For this, a section called hooks is defined in the install_json file, and the endpoint that is supposed to respond to the hooks is set along with the events that should be called by this endpoint.

Now when the user reaches the "before-new-install" point (when he clicks the install button), a request from ArvanCloud's API side to "http://example-vendor.com/hook" with a specific payload that we will examine below, is sent. At this stage, the application developer can check the payload, view the user's inputs, perform the registration, change the inputs or even return an error and stop the installation process and display the error to the user.


*Registration by this method is not recommended and it is better to do it through the OAth, but until the implementation, you can use this way.

Structure

The simplest hook structure is as follows:

  "hooks": [
{
"endpoint": "https://example.com/my-endpoint",
"events": [
"before-new-install"
]
}
]
  • Endpoint

    The HTTPS address of the server that responds to hooks.

  • Events

    An array of events (see the Events section.)

    It is possible to connect several different hooks to the same event. It is also possible to listen to several different events for one endpoint.

Events

  • Before-new-install

When the user clicks the install button and this event is fired before the install, the install object can be modified, the user can be shown an error, or the installation process can be stopped.

Request Payloads

Example of a request that the specified webhook address receives from ArvanCloud:

{
"event": "before-new-install",
"user": {
"id": "003d7fb3-4108-43cd-b7c5-19a4c8cb2e51",
"email": "arvanuser@gmail.com"
},
"site": {
"id": "67bd92d3-cde1-45f5-91e2-32a021f7752c",
"name": "example.ir",
"owner_id": "393f1d23-80ee-4872-917c-1bca8a150d69"
},
"install": {
"options": {
"color": "filled-by-user",
"token": "webhook-server-will-fill-this"
},
"schema": {
"properties": {
"color": {
"title": "desired color",
"description": "tell us whats your favorite color",
"type": "string"
},
"token": {
"title": "token by hook",
"description": "The token will be automatically generated for you, we register you as our customer with your arvan's email address",
"type": "string"
}
},
"required": [
"color",
"token"
]
}
},
"app": { /* Your app */
"id": "21493101-cda6-4a48-8ef5-e1b5da6941df",
"name": "ref-hook",
"slug": "ref-hook"
}
}
  • event

    The name of the event that caused the webhook to be called.

  • user

    Profile of the user who is installing the program.

  • site

    The website on which the application is installed.

  • install

    • options

      User entries so far can be seen and even edited in this field.

    • schema

      The same options are in the install_json file that specifies the input structure, this field is currently read-only (changes will not have any effect), but in future versions, the webhook can change the schema according to user inputs so that more complex programs can be installed easily to implement.

  • app

    Profiles registered in ArvanCloud for the application being installed

Hook Response Format

The webhook response should be in the following format:

{
proceed: Boolean /* Should we allow this action to proceed? */,
errors: [error] /* array of errors which occured while you attempted to handle this event. */,
install: Object { /* The newly updated install record incorporating your changes. */ }
}
  • proceed

    If it is false, the installation process will stop and the error will be displayed to the user.

  • errors

    An array of errors occurred while checking the request in the following format:

    {
    type: String /* A string representing a code for this error which will not change frequently. */,
    message: String /* A human readable English-language explanation of the error to be displayed. */
    }

    example:

      "errors": [
    {
    "type": "error 422",
    "message": "The value of color must in hexadecimal format"
    }
    ]

Hook Security

ArvanCloud, when sending a request to the hook server, hashes the entire body of the request (uncompressed) with a secret using the SHA-256 HMAC algorithm and puts it in the x-signature-hmac-sha256-hex header. The webhook is also required to do this and compare it with the header and reject the request if the header is wrong.

An Example of Verifying in Laravel

      $hash = hash_hmac('sha256', $request->getContent(), 'my-app-secret');
if ($hash !== $request->header('x-signature-hmac-sha256-hex')) {
abort(401, "Hook signature does not match");
}
// proceed ...

The length of the secret is equal to 128 characters and the length of the hash is equal to 64 characters. Both of them are presented in hexadecimal number format.

How to Make a Multilingual Program

To translate the program information (name, short and long description) when defining it, a field in Json format must be sent by the admin as shown below.

Of course, note that it is not necessary to translate all the information for all languages, because if a key is not defined, the default value (values defined by the program) will be sent to the client.

"info_translations": {
"en": {
"name": "english_name",
"short_description": "english_short_description",
"description": "english_description"
},
"fa": {
"name": "persian_name",
"short_description": "persian_short_description",
"description": "persian_description"
}
}

Implementation Limits

If you are familiar with CDN applications, you should know that the current version of cdn-app or ArvanCloud marketplace includes the following limits:

  • No ability to change form during installation

  • Being able to use only three types string, integer, and boolean to use in the form

  • Lack of OAuth support

  • No ability to use resources in separate files and specify the path (all js and CSS content must be included in the install.json file.)

  • Currently, only the before-new-install webhook can be used