### Custom DNS Provider - List Zones Response Example Source: https://github.com/shibayan/keyvault-acmebot/wiki/DNS-Provider-Configuration An example JSON structure for the response when listing zones from a custom DNS provider API. It includes the zone ID, name, and optional nameservers, which are required for Key Vault Acmebot to interact with the custom DNS service. ```json [ { "id": "example_com", "name": "example.com", "nameServers": ["x.x.x.x", "y.y.y.y"] } ] ``` -------------------------------- ### Acquire Azure AD Access Token and Call API (C#) Source: https://github.com/shibayan/keyvault-acmebot/wiki/Authentication-Methods-for-REST-API This C# code snippet shows how to use the Microsoft Authentication Library (MSAL) to acquire an Azure AD access token for a client application. It then uses this token to make an authenticated HTTP GET request to an Azure Functions API. This method requires client ID, client secret, tenant ID, and application URI. The output is the string response from the API. ```csharp using System.Net.Http.Headers; using Microsoft.Identity.Client; var app = ConfidentialClientApplicationBuilder.Create("") .WithClientSecret("") .WithTenantId("") .Build(); var token = await app.AcquireTokenForClient(new[] { "/.default" }).ExecuteAsync(); var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken); var response = await httpClient.GetStringAsync("https://***.azurewebsites.net/api/certificates"); Console.WriteLine(response); ``` -------------------------------- ### Retrieve Functions Host Key for API Call (C#) Source: https://github.com/shibayan/keyvault-acmebot/wiki/Authentication-Methods-for-REST-API This C# code snippet demonstrates how to retrieve a Functions host key and use it to make an authenticated HTTP GET request to an Azure Functions API. It requires the 'X-Functions-Key' header to be set with the obtained key. The output is the string response from the API. ```csharp var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.TryAddWithoutValidation("X-Functions-Key", ""); var response = await httpClient.GetStringAsync("https://***.azurewebsites.net/api/certificates"); Console.WriteLine(response); ``` -------------------------------- ### Custom DNS Provider - Upsert Record Request Example Source: https://github.com/shibayan/keyvault-acmebot/wiki/DNS-Provider-Configuration This JSON object represents the request body format for upserting a DNS record via a custom DNS provider's API. It specifies the record type, Time To Live (TTL), and the record values, which Key Vault Acmebot will send to update DNS entries. ```json { "type": "TXT", "ttl": 60, "values": ["xxxxxx", "yyyyyy"] } ``` -------------------------------- ### GET zones Source: https://github.com/shibayan/keyvault-acmebot/wiki/DNS-Provider-Configuration Lists available DNS zones for the custom DNS provider. This endpoint is used by Acmebot to enumerate zones before performing DNS-01 challenges. The response includes zone ID, name, and optional name servers. ```APIDOC ## GET zones ### Description Retrieves a list of DNS zones available in the custom DNS provider. ### Method GET ### Endpoint zones ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Request Example No request body required. ### Response #### Success Response (200) - **id** (string) - Required. Unique identifier for the zone (e.g., example_com) - **name** (string) - Required. The domain name of the zone (e.g., example.com) - **nameServers** (array of strings) - Optional. List of name server addresses #### Response Example [{ "id": "example_com", "name": "example.com", "nameServers": ["x.x.x.x", "y.y.y.y"] }] #### Error Responses - 401 Unauthorized: Invalid API key - 500 Internal Server Error: Provider-specific error ``` -------------------------------- ### Async Request Polling (GET) Source: https://github.com/shibayan/keyvault-acmebot/wiki/REST-API HTTP GET request to poll the status of an asynchronous operation, using the location URL provided in previous responses. ```http GET /api/state/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` -------------------------------- ### Amazon Route 53 IAM Policy Example Source: https://github.com/shibayan/keyvault-acmebot/wiki/DNS-Provider-Configuration This JSON policy grants Key Vault Acmebot the necessary permissions to manage DNS records in Amazon Route 53. It allows changing record sets within a specific hosted zone and listing all hosted zones. ```json { "Sid": "VisualEditor1", "Effect": "Allow", "Action": [ "route53:ChangeResourceRecordSets", "route53:ListResourceRecordSets" ], "Resource": "arn:aws:route53:::hostedzone/YOUR_ZONE_ID" }, { "Sid": "VisualEditor2", "Effect": "Allow", "Action": "route53:ListHostedZones", "Resource": "*" } ``` -------------------------------- ### Modal and Data Loading Functions Source: https://github.com/shibayan/keyvault-acmebot/blob/master/KeyVault.Acmebot/wwwroot/dashboard/index.html Includes functions to open modal dialogs for adding new records or viewing details, and to load initial data. The `openAdd` function initializes form fields and loads DNS zones, while `openDetails` sets the certificate for display. `beforeMount` triggers a general load operation. ```javascript async openAdd() { this.add.recordName = ""; this.add.dnsNames = []; this.add.dnsProviderName = ""; this.add.certificateName = ""; this.add.modalActive = true; await this.loadDnsZones(); }, openDetails(certificate) { this.details.certificate = certificate; this.details.modalActive = true; }, async beforeMount() { await this.load(); } ``` -------------------------------- ### JavaScript: Certificate Management and Operations Source: https://github.com/shibayan/keyvault-acmebot/blob/master/KeyVault.Acmebot/wwwroot/dashboard/index.html This JavaScript code defines the main application logic for the Key Vault Acmebot. It handles fetching certificate data, refreshing the list, loading DNS zones, adding DNS names, and initiating the certificate addition process. It utilizes Axios for HTTP requests and includes asynchronous operations with delays. ```javascript const delay = (millisecondsDelay) => { return new Promise(resolve => setTimeout(() => resolve(), millisecondsDelay)); } const app = { data() { return { certificates: [], loading: false, add: { zones: {}, zone: null, recordName: "", dnsNames: [], dnsProviderName: "", useAdvancedOptions: false, certificateName: "", keyType: "RSA", keySize: "2048", keyCurveName: "P-256", reuseKey: false, loading: false, sending: false, modalActive: false }, details: { certificate: "", sending: false, modalActive: false } }; }, computed: { managedCertificates() { return this.certificates.filter(x => x.isIssuedByAcmebot && x.isSameEndpoint); }, anotherCACertificates() { return this.certificates.filter(x => x.isIssuedByAcmebot && !x.isSameEndpoint); }, unmanagedCertificates() { return this.certificates.filter(x => !x.isIssuedByAcmebot && !x.isIssuedByAcmebot); } }, methods: { async load() { this.loading = true; try { const response = await axios.get("/api/certificates"); if (response.status === 200) { this.certificates = response.data.sort((x, y) => x.expiresOn.localeCompare(y.expiresOn)); } } catch (error) { this.handleHttpError(error); } this.loading = false; }, async refresh() { Object.assign(this.$data, this.$options.data()); await this.load(); }, async loadDnsZones() { this.add.loading = true; this.add.zone = null; try { const response = await axios.get("/api/dns-zones"); if (response.status === 200) { this.add.zones = response.data; } } catch (error) { this.handleHttpError(error); } this.add.loading = false; }, addDnsName() { if (this.add.zone === null) { return; } if (this.add.dnsProviderName !== "" && this.add.dnsProviderName !== this.add.zone.dnsProviderName) { alert("DNS zones belonging to different DNS Providers cannot be included in the same certificate."); return; } const dnsName = this.add.recordName === "" ? this.add.zone.name : punycode.toASCII(this.add.recordName) + "." + this.add.zone.name; if (this.add.dnsNames.indexOf(dnsName) === -1) { this.add.dnsNames.push(dnsName); } this.add.dnsProviderName = this.add.zone.dnsProviderName; this.add.recordName = ""; }, removeDnsName(dnsName) { this.add.dnsNames = this.add.dnsNames.filter(x => x !== dnsName); if (this.add.dnsNames.length === 0) { this.add.dnsProviderName = ""; } }, async addCertificate() { this.add.sending = true; const postData = { dnsNames: this.add.dnsNames, dnsProviderName: this.add.dnsProviderName, certificateName: this.add.certificateName, keyType: this.add.keyType, reuseKey: this.add.reuseKey }; if (this.add.keyType === "RSA") { postData.keySize = this.add.keySize; } else { postData.keyCurveName = this.add.keyCurveName; } try { let response = await axios.post("/api/certificate", postData); while (true) { await delay(5000); response = await axios.get(response.headers["location"]); if (response.status === 200) { alert("The certificate was successfully issued."); break; } } } catch (error) { this.handleHttpError(error); } this.add.sending = false; this.add.modalActive = false; await this.refresh(); } } }; ``` -------------------------------- ### Punycode Conversion Source: https://github.com/shibayan/keyvault-acmebot/blob/master/KeyVault.Acmebot/wwwroot/dashboard/index.html Converts Internationalized Domain Names (IDNs) to their Punycode representation for compatibility. This function relies on the 'punycode' library. Input is a string, and the output is the Punycode-encoded string. ```javascript toUnicode(value) { return punycode.toUnicode(value); } ``` -------------------------------- ### Issue Certificate Response (202 Accepted) Source: https://github.com/shibayan/keyvault-acmebot/wiki/REST-API Successful response for issuing a certificate, indicating the request has been accepted and providing a location URL to poll for status. ```http 202 Accepted Location: /api/state/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` -------------------------------- ### Date Formatting and Expiration Calculation Source: https://github.com/shibayan/keyvault-acmebot/blob/master/KeyVault.Acmebot/wwwroot/dashboard/index.html Provides functions to format dates into a readable string and to calculate the remaining days until a certificate expires. The expiration function returns a string indicating days remaining or if the certificate has expired. Dependencies include the built-in Date object. ```javascript formatCreatedOn(value) { return new Date(value).toLocaleString(); }, formatExpiresOn(value) { const date = new Date(value); const diff = date - Date.now(); const remainDays = Math.round(diff / (1000 * 60 * 60 * 24)); const remainText = diff > 0 ? `Expires in ${remainDays} days` : `EXPIRED`; return `${date.toLocaleString()} (${remainText})`; } ``` -------------------------------- ### Certificate Revocation Logic Source: https://github.com/shibayan/keyvault-acmebot/blob/master/KeyVault.Acmebot/wwwroot/dashboard/index.html Manages the revocation of a certificate after user confirmation. It sends a POST request to the API and alerts the user upon successful revocation or handles HTTP errors. Dependencies include a confirmation prompt and Axios for requests. ```javascript async revokeCertificate() { if (!confirm(`${this.details.certificate.name} revoke your certificate. Are you sure?`)) { return; } this.details.sending = true; try { const response = await axios.post(`/api/certificate/${this.details.certificate.name}/revoke`); if (response.status === 200) { alert("The certificate was successfully revoked."); } } catch (error) { this.handleHttpError(error); } this.details.sending = false; this.details.modalActive = false; } ``` -------------------------------- ### Issue Certificate Response (400 Bad Request) Source: https://github.com/shibayan/keyvault-acmebot/wiki/REST-API Error response when the request to issue a certificate is invalid, typically due to missing or improperly formatted DNS names. ```json { "errors": { "DnsNames": [ "The DnsNames is required." ] }, "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-e2468d29d2988e4490e92e2768b622b0-92d30024b7066e4d-00" } ``` -------------------------------- ### Certificate Renewal Logic Source: https://github.com/shibayan/keyvault-acmebot/blob/master/KeyVault.Acmebot/wwwroot/dashboard/index.html Handles the renewal of a certificate by making a POST request to the API and polling for the completion status. It alerts the user upon success or handles HTTP errors. Dependencies include Axios for requests and a delay function. ```javascript async renewCertificate() { this.details.sending = true; try { let response = await axios.post(`/api/certificate/${this.details.certificate.name}/renew`); while (true) { await delay(5000); response = await axios.get(response.headers["location"]); if (response.status === 200) { alert("The certificate was successfully renewed."); break; } } } catch (error) { this.handleHttpError(error); } this.details.sending = false; this.details.modalActive = false; await this.refresh(); } ``` -------------------------------- ### Issue Certificate Source: https://github.com/shibayan/keyvault-acmebot/wiki/REST-API Issues a new certificate for the specified DNS names. This is an asynchronous operation, and the response will contain a location header to poll for the status. ```APIDOC ## POST /api/certificate ### Description Issues a new certificate for the specified DNS names. This is an asynchronous operation, and the response will contain a location header to poll for the status. ### Method POST ### Endpoint /api/certificate ### Parameters #### Query Parameters - **X-Functions-Key** (string) - Required - Functions Host Key - **Content-Type** (string) - Required - application/json #### Request Body - **DnsNames** (array of strings) - Required - A list of DNS names for which to issue the certificate. ### Request Example ```json { "DnsNames": ["contoso.com", "www.contoso.com"] } ``` ### Response #### Success Response (202 Accepted) - **Location** (string) - The URL to poll for the status of the certificate issuance operation. #### Response Example ``` 202 Accepted Location: /api/state/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` #### Error Response (400 Bad Request) - **errors** (object) - Contains validation errors. - **type** (string) - The URI that identifies the error type. - **title** (string) - A short, human-readable summary of the error. - **status** (integer) - The HTTP status code. - **traceId** (string) - A unique identifier for the request trace. #### Response Example (400 Bad Request) ```json { "errors": { "DnsNames": [ "The DnsNames is required." ] }, "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-e2468d29d2988e4490e92e2768b622b0-92d30024b7066e4d-00" } ``` #### Error Response (401 Unauthorized) ``` 401 Unauthorized ``` ``` -------------------------------- ### HTTP Error Handling Source: https://github.com/shibayan/keyvault-acmebot/blob/master/KeyVault.Acmebot/wwwroot/dashboard/index.html A utility function to process and display HTTP errors. It differentiates between bad requests (400) with validation errors and other HTTP status codes, displaying specific messages or generic error notifications. Dependencies include Axios error objects. ```javascript handleHttpError(error) { const problem = error.response.data; if (error.response.status === 400) { const errors = []; for (let key in problem.errors) { errors.push(problem.errors[key][0]); } alert(errors.join("\n")); } else { const message = problem.detail ?? problem.output; if (message) { alert(message); } else { alert(`HTTP Response ${error.response.status} Error`); } } } ``` -------------------------------- ### PUT zones/{zoneId}/records/{recordName} Source: https://github.com/shibayan/keyvault-acmebot/wiki/DNS-Provider-Configuration Creates or updates a DNS record in the specified zone, typically for ACME challenge validation. This endpoint supports updating TXT records for DNS-01 challenges with specified TTL and values. ```APIDOC ## PUT zones/{zoneId}/records/{recordName} ### Description Upserts a DNS record in the given zone, allowing creation or modification of records such as TXT entries for ACME challenges. ### Method PUT ### Endpoint zones/{zoneId}/records/{recordName} ### Parameters #### Path Parameters - **zoneId** (string) - Required. The zone identifier (e.g., example_com) - **recordName** (string) - Required. The record name, including subdomain (e.g., _acme-challenge.example.com) #### Query Parameters - None #### Request Body - **type** (string) - Required. Record type (e.g., TXT) - **ttl** (integer) - Required. Time-to-live in seconds - **values** (array of strings) - Required. Array of record values ### Request Example { "type": "TXT", "ttl": 60, "values": ["xxxxxx", "yyyyyy"] } ### Response #### Success Response (200) - No content response, or provider-specific confirmation #### Response Example { "success": true } #### Error Responses - 400 Bad Request: Invalid request body - 404 Not Found: Zone or record not found - 401 Unauthorized: Invalid API key - 500 Internal Server Error: Provider-specific error ``` -------------------------------- ### Issue Certificate Response (401 Unauthorized) Source: https://github.com/shibayan/keyvault-acmebot/wiki/REST-API Error response indicating that the request to issue a certificate is unauthorized due to missing or invalid host keys. ```http 401 Unauthorized ``` -------------------------------- ### Issue Certificate Request Payload (JSON) Source: https://github.com/shibayan/keyvault-acmebot/wiki/REST-API The JSON payload required to issue a new certificate. It must include a list of DNS names for which the certificate will be valid. ```json { "DnsNames": ["contoso.com", "www.contoso.com"] } ``` -------------------------------- ### DELETE zones/{zoneId}/records/{recordName} Source: https://github.com/shibayan/keyvault-acmebot/wiki/DNS-Provider-Configuration Removes a DNS record from the specified zone, used after ACME challenge completion to clean up temporary records like TXT entries for _acme-challenge. ```APIDOC ## DELETE zones/{zoneId}/records/{recordName} ### Description Deletes the specified DNS record from the zone, facilitating cleanup of challenge records post-validation. ### Method DELETE ### Endpoint zones/{zoneId}/records/{recordName} ### Parameters #### Path Parameters - **zoneId** (string) - Required. The zone identifier - **recordName** (string) - Required. The record name to delete #### Query Parameters - None #### Request Body - None ### Request Example No request body required. ### Response #### Success Response (200) - No content response, or provider-specific confirmation #### Response Example { "success": true } #### Error Responses - 404 Not Found: Zone or record not found - 401 Unauthorized: Invalid API key - 500 Internal Server Error: Provider-specific error ``` -------------------------------- ### Async Request Polling Response (200 OK) Source: https://github.com/shibayan/keyvault-acmebot/wiki/REST-API Successful response when polling for the status of an asynchronous operation, indicating the operation has completed. ```http 200 OK ``` -------------------------------- ### Revoke Certificate Source: https://github.com/shibayan/keyvault-acmebot/wiki/REST-API Revokes an existing certificate. This is an asynchronous operation, and the response will contain a location header to poll for the status. ```APIDOC ## POST /api/certificate/{certificate-name}/revoke ### Description Revokes an existing certificate. This is an asynchronous operation, and the response will contain a location header to poll for the status. ### Method POST ### Endpoint /api/certificate/{certificate-name}/revoke ### Parameters #### Path Parameters - **certificate-name** (string) - Required - The name of the certificate to revoke. #### Query Parameters - **X-Functions-Key** (string) - Required - Functions Host Key ### Response #### Success Response (202 Accepted) - **Location** (string) - The URL to poll for the status of the certificate revocation operation. #### Response Example ``` 202 Accepted Location: /api/state/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` #### Error Response (401 Unauthorized) ``` 401 Unauthorized ``` ``` -------------------------------- ### Renew Certificate Source: https://github.com/shibayan/keyvault-acmebot/wiki/REST-API Renews an existing certificate. This is an asynchronous operation, and the response will contain a location header to poll for the status. ```APIDOC ## POST /api/certificate/{certificate-name}/renew ### Description Renews an existing certificate. This is an asynchronous operation, and the response will contain a location header to poll for the status. ### Method POST ### Endpoint /api/certificate/{certificate-name}/renew ### Parameters #### Path Parameters - **certificate-name** (string) - Required - The name of the certificate to renew. #### Query Parameters - **X-Functions-Key** (string) - Required - Functions Host Key ### Response #### Success Response (202 Accepted) - **Location** (string) - The URL to poll for the status of the certificate renewal operation. #### Response Example ``` 202 Accepted Location: /api/state/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` #### Error Response (401 Unauthorized) ``` 401 Unauthorized ``` ``` -------------------------------- ### Renew Certificate Request Source: https://github.com/shibayan/keyvault-acmebot/wiki/REST-API HTTP POST request to renew a specific certificate, identified by its name in the URL path. ```http POST /api/certificate/{certificate-name}/renew ``` -------------------------------- ### Revoke Certificate Request Source: https://github.com/shibayan/keyvault-acmebot/wiki/REST-API HTTP POST request to revoke a specific certificate, identified by its name in the URL path. ```http POST /api/certificate/{certificate-name}/revoke ``` -------------------------------- ### Poll Async Request Status Source: https://github.com/shibayan/keyvault-acmebot/wiki/REST-API Polls the status of an asynchronous operation (e.g., certificate issuance, renewal, or revocation) using the provided state URL. ```APIDOC ## GET /api/state/{state-id} ### Description Polls the status of an asynchronous operation (e.g., certificate issuance, renewal, or revocation) using the provided state URL. ### Method GET ### Endpoint /api/state/{state-id} ### Parameters #### Path Parameters - **state-id** (string) - Required - The unique identifier for the asynchronous operation's state. #### Query Parameters - **X-Functions-Key** (string) - Required - Functions Host Key ### Response #### Success Response (200 OK) Indicates the operation has completed successfully. The response body would typically contain details about the completed operation. #### Response Example (200 OK) ``` 200 OK ``` #### Accepted Response (202 Accepted) Indicates the operation is still in progress. The response may contain a `Location` header if the operation needs to be polled further. #### Response Example (202 Accepted) ``` 202 Accepted Location: /api/state/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` #### Error Response (500 Internal Server Error) Indicates a server-side error occurred during the operation. #### Response Example (500 Internal Server Error) ``` 500 Internal Server Error ``` ``` -------------------------------- ### Async Request Polling Response (500 Internal Server Error) Source: https://github.com/shibayan/keyvault-acmebot/wiki/REST-API Error response when polling for the status of an asynchronous operation, indicating a server-side error occurred. ```http 500 Internal Server Error ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.