Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 77 additions & 1 deletion lib/provisioning/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,77 @@ function user_group_users(group_id, options = {}, callback) {
return call_account_api('GET', uri, {}, callback, options);
}

/**
* @desc Lists access keys in the given subaccount.
* @param sub_account_id {string} - The ID of the subaccount.
* @param [options] {object} - See {@link https://cloudinary.com/documentation/provisioning_api#tag/access-keys/GET/sub_accounts/{{sub_account_id}}/access_keys|get access keys optional parameters} in the SDK documentation.
* @param [callback] {function}
*/
function access_keys(sub_account_id, options = {}, callback) {
const params = pickOnlyExistingValues({
page_size: options.page_size,
page: options.page,
sort_by: options.sort_by,
sort_order: options.sort_order
}, 'page_size', 'page', 'sort_by', 'sort_order');
const uri = ['sub_accounts', sub_account_id, 'access_keys'];
return call_account_api('GET', uri, params, callback, options);
}

/**
* @desc Generate a new access key pair in the given subaccount.
* @param sub_account_id {string} - The ID of the subaccount.
* @param [options] {object} - See {@link https://cloudinary.com/documentation/provisioning_api#tag/access-keys/POST/sub_accounts/{{sub_account_id}}/access_keys|generate access key optional parameters} in the SDK documentation.
* @param [callback] {function}
*/
function generate_access_key(sub_account_id, options = {}, callback) {
const params = pickOnlyExistingValues({
name: options.name,
enabled: options.enabled
}, 'name', 'enabled');
options.content_type = "json";
const uri = ['sub_accounts', sub_account_id, 'access_keys'];
return call_account_api('POST', uri, params, callback, options);
}

/**
* @desc Update an existing access key pair in the given subaccount.
* @param sub_account_id {string} - The ID of the subaccount.
* @param [options] {object} - See {@link https://cloudinary.com/documentation/provisioning_api#tag/access-keys/PUT/sub_accounts/{sub_account_id}/access_keys/{key}|update access key optional parameters} in the SDK documentation.
* @param [callback] {function}
*/
function update_access_key(sub_account_id, api_key, options = {}, callback) {
const params = pickOnlyExistingValues({
name: options.name,
enabled: options.enabled
}, 'name', 'enabled');
options.content_type = "json";
const uri = ['sub_accounts', sub_account_id, 'access_keys', api_key];
return call_account_api('PUT', uri, params, callback, options);
}

/**
* @desc Delete an existing access key pair in the given subaccount.
* @param sub_account_id {string} - The ID of the subaccount.
* @param [options] {object} - See {@link https://cloudinary.com/documentation/provisioning_api#tag/access-keys/DELETE/sub_accounts/{sub_account_id}/access_keys|delete access key optional parameters} in the SDK documentation.
* @param [callback] {function}
*/
function delete_access_key(sub_account_id, api_key, options = {}, callback) {
const uri = ['sub_accounts', sub_account_id, 'access_keys', api_key];
return call_account_api('DELETE', uri, {}, callback, options);
}

/**
* @desc Delete an existing access key pair in the given subaccount by its name.
* @param sub_account_id {string} - The ID of the subaccount.
* @param [options] {object} - See {@link https://cloudinary.com/documentation/provisioning_api#tag/access-keys/DELETE/sub_accounts/{sub_account_id}/access_keys|delete access key optional parameters} in the SDK documentation.
* @param [callback] {function}
*/
function delete_access_key_by_name(sub_account_id, options = {}, callback) {
const params = { name: options.name };
const uri = ['sub_accounts', sub_account_id, 'access_keys'];
return call_account_api('DELETE', uri, params, callback, options);
}

module.exports = {
sub_accounts,
Expand All @@ -310,5 +381,10 @@ module.exports = {
create_user,
create_user_group,
add_user_to_group,
delete_user_group
delete_user_group,
access_keys,
generate_access_key,
update_access_key,
delete_access_key,
delete_access_key_by_name
};
122 changes: 122 additions & 0 deletions test/integration/api/provisioning/access_keys_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
const cloudinary = require("../../../../cloudinary");
const TIMEOUT = require('../../../testUtils/testConstants').TIMEOUT;
let runOnlyForInternalPRs = process.env.TRAVIS_SECURE_ENV_VARS ? describe : describe.skip;


describe.skip('Provisioning API - Access Keys Management', function () {
let CLOUD_SECRET;
let CLOUD_API;
let CLOUD_NAME;
let CLOUD_ID;
let CLOUD_NAME_PREFIX = `justaname${process.hrtime()[1] % 10000}`;
this.timeout(TIMEOUT.LONG);

before("Setup the required test", async () => {
let config = cloudinary.config(true);
if (!(config.provisioning_api_key && config.provisioning_api_secret && config.account_id)) {
// For external PRs the env variables are not availble, so we skip the provisioning API
this.skip();
}

let CLOUD_TO_CREATE = CLOUD_NAME_PREFIX + Date.now();
// Create a sub account(sub cloud)
let res = await cloudinary.provisioning.account.create_sub_account(CLOUD_TO_CREATE, CLOUD_TO_CREATE, {}, true).catch((err) => {
throw err;
});

CLOUD_API = res.api_access_keys[0].key;
CLOUD_SECRET = res.api_access_keys[0].secret;
CLOUD_NAME = res.cloud_name;
CLOUD_ID = res.id;

return true;
});

after('Destroy the sub_account and users that were created', async () => {
// Skip 'after' in case we don't have account configuration available
// This means that the beforeHook also didn't run
let config = cloudinary.config(true);
if (!(config.provisioning_api_key && config.provisioning_api_secret && config.account_id)) {
return;
}

const delRes = await cloudinary.provisioning.account.delete_sub_account(CLOUD_ID);
expect(delRes.message).to.eql('ok');
});

it('List access keys', async () => {
const accessKeys = await cloudinary.provisioning.account.access_keys(CLOUD_ID);
expect(Object.keys(accessKeys)).to.eql(['access_keys', 'total']);
expect(accessKeys.access_keys.length).to.eql(1);
expect(Object.keys(accessKeys.access_keys[0])).to.eql(['name', 'api_key', 'api_secret', 'created_at', 'updated_at', 'enabled']);
});

it('Generate new access key', async () => {
const keyName = `test-access-key-${Date.now()}`
const newAccessKey = await cloudinary.provisioning.account.generate_access_key(CLOUD_ID, { name: keyName });
expect(Object.keys(newAccessKey)).to.eql(['name', 'api_key', 'api_secret', 'created_at', 'updated_at', 'enabled']);
expect(newAccessKey.name).to.eql(keyName);
});

it('List access keys with optional query params', async () => {
const keyName1 = `A-test-access-key-${Date.now()}`
const newAccessKey1 = await cloudinary.provisioning.account.generate_access_key(CLOUD_ID, { name: keyName1 });
expect(Object.keys(newAccessKey1)).to.eql(['name', 'api_key', 'api_secret', 'created_at', 'updated_at', 'enabled']);
expect(newAccessKey1.name).to.eql(keyName1);

const keyName2 = `B-test-access-key-${Date.now()}`
const newAccessKey2 = await cloudinary.provisioning.account.generate_access_key(CLOUD_ID, { name: keyName2 });
expect(Object.keys(newAccessKey2)).to.eql(['name', 'api_key', 'api_secret', 'created_at', 'updated_at', 'enabled']);
expect(newAccessKey2.name).to.eql(keyName2);

const keyName3 = `C-test-access-key-${Date.now()}`
const newAccessKey3 = await cloudinary.provisioning.account.generate_access_key(CLOUD_ID, { name: keyName3 });
expect(Object.keys(newAccessKey3)).to.eql(['name', 'api_key', 'api_secret', 'created_at', 'updated_at', 'enabled']);
expect(newAccessKey3.name).to.eql(keyName3);

const pageSize = 2;
const accessKeys = await cloudinary.provisioning.account.access_keys(CLOUD_ID, {
page_size: pageSize,
page: 1,
sort_by: 'name',
sort_order: 'desc'
});
expect(Object.keys(accessKeys)).to.eql(['access_keys', 'total']);
expect(accessKeys.access_keys.length).to.eql(pageSize);
expect(Object.keys(accessKeys.access_keys[0])).to.eql(['name', 'api_key', 'api_secret', 'created_at', 'updated_at', 'enabled']);
});

it('Update access key', async () => {
const keyName = `test-access-key-${Date.now()}`
const newAccessKey = await cloudinary.provisioning.account.generate_access_key(CLOUD_ID, { name: keyName });
expect(Object.keys(newAccessKey)).to.eql(['name', 'api_key', 'api_secret', 'created_at', 'updated_at', 'enabled']);
expect(newAccessKey.name).to.eql(keyName);

const newName = `${keyName}-updated`;
const updatedAccessKey = await cloudinary.provisioning.account.update_access_key(CLOUD_ID, newAccessKey.api_key, { name: newName });
expect(Object.keys(newAccessKey)).to.eql(['name', 'api_key', 'api_secret', 'created_at', 'updated_at', 'enabled']);
expect(updatedAccessKey.name).to.eql(newName);
});

it('Delete access keys', async () => {
const keyName = `test-access-key-${Date.now()}`
const newAccessKey = await cloudinary.provisioning.account.generate_access_key(CLOUD_ID, { name: keyName });
expect(Object.keys(newAccessKey)).to.eql(['name', 'api_key', 'api_secret', 'created_at', 'updated_at', 'enabled']);
expect(newAccessKey.name).to.eql(keyName);

const deleteAccessKey = await cloudinary.provisioning.account.delete_access_key(CLOUD_ID, newAccessKey.api_key);
expect(Object.keys(deleteAccessKey)).to.eql(['message']);
expect(deleteAccessKey.message).to.eql('ok');
});

it('Delete access keys by name', async () => {
const keyName = `test-access-key-${Date.now()}`
const newAccessKey = await cloudinary.provisioning.account.generate_access_key(CLOUD_ID, { name: keyName });
expect(Object.keys(newAccessKey)).to.eql(['name', 'api_key', 'api_secret', 'created_at', 'updated_at', 'enabled']);
expect(newAccessKey.name).to.eql(keyName);

const deleteAccessKey = await cloudinary.provisioning.account.delete_access_key_by_name(CLOUD_ID, { name: keyName });
expect(Object.keys(deleteAccessKey)).to.eql(['message']);
expect(deleteAccessKey.message).to.eql('ok');
});
});
41 changes: 41 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,24 @@ declare module 'cloudinary' {
[futureKey: string]: any;
}

export interface AccessKeyDetails {
name: string,
api_key: string,
api_secret: string,
created_at: string,
updated_at: string,
enabled: boolean
}

export interface AccessKeysListResponse {
access_keys: Array<AccessKeyDetails>,
total: number
}

export interface DeleteAccessKeyResponse {
message: 'ok' | 'not_found'
}

export interface AuthTokenApiOptions {
key: string;
acl: string;
Expand Down Expand Up @@ -1485,6 +1503,29 @@ declare module 'cloudinary' {
function user_groups(options?: ProvisioningApiOptions, callback?: ResponseCallback): Promise<any>;

function user_group_users(groupId: string, options?: ProvisioningApiOptions, callback?: ResponseCallback): Promise<any>;

function access_keys(subAccountId: string, options?: ProvisioningApiOptions | {
page_size?: number,
page?: number,
sort_by?: string,
sort_order?: 'desc' | 'asc'
}, callback?: ResponseCallback): Promise<AccessKeysListResponse>;

function generate_access_key(subAccountId: string, options?: ProvisioningApiOptions | {
name?: string,
enabled?: boolean
}, callback?: ResponseCallback): Promise<AccessKeyDetails>;

function update_access_key(subAccountId: string, apiKey: string, options?: ProvisioningApiOptions | {
name?: string,
enabled?: boolean
}, callback?: ResponseCallback): Promise<AccessKeyDetails>;

function delete_access_key(subAccountId: string, apiKey: string, options?: ProvisioningApiOptions, callback?: ResponseCallback): Promise<DeleteAccessKeyResponse>;

function delete_access_key_by_name(subAccountId: string, options: ProvisioningApiOptions | {
name: string,
}, callback?: ResponseCallback): Promise<DeleteAccessKeyResponse>;
}
}

Expand Down