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
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
### Pull reuqest for @Cloudianry/Base
### Pull request for @Cloudinary/Base


#### What does this PR solve?
Expand Down
8 changes: 2 additions & 6 deletions __TESTS__/unit/config/cloudinaryConfig.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,10 @@ describe('Tests for CloudinaryConfiguration', () => {
signUrl: true,
longUrlSignature: true,
useRootPath: true,
cdnSubdomain: true,
cname: 'cname',
secureCdnSubdomain: true,
privateCdn: true,
secure: true,
secureDistribution: true
secureDistribution: ''
}
});

Expand All @@ -58,12 +56,10 @@ describe('Tests for CloudinaryConfiguration', () => {
expect(conf.url.signUrl).toBe(true);
expect(conf.url.longUrlSignature).toBe(true);
expect(conf.url.useRootPath).toBe(true);
expect(conf.url.cdnSubdomain).toBe(true);
expect(conf.url.cname).toBe('cname');
expect(conf.url.secureCdnSubdomain).toBe(true);
expect(conf.url.privateCdn).toBe(true);
expect(conf.url.secure).toBe(true);
expect(conf.url.secureDistribution).toBe(true);
expect(conf.url.secureDistribution).toBe('');

});

Expand Down
74 changes: 73 additions & 1 deletion __TESTS__/unit/urlConfig.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
import TransformableImage from "../../src/transformation/TransformableImage";
import * as Resize from "../../src/actions/resize/Resize";
import ICloudinaryConfigurations from "../../src/interfaces/Config/ICloudinaryConfigurations";
import IURLConfig from "../../src/interfaces/Config/IURLConfig";
import CloudinaryConfig from "../../src/config/CloudinaryConfig";
import createCloudinaryURL from "../../src/url/cloudinaryURL";

/**
* @description Create CloudinaryURL based on a URL Configuration, and return the URL
* @param urlConfig
*/
function createURLFromConfig(urlConfig: IURLConfig) {
const conf = new CloudinaryConfig({
cloud: {
cloudName: 'demo'
},
url: urlConfig
});

return createCloudinaryURL(conf, { publicID: 'sample' });
}

const DEMO_CONFIG = {
cloud: {
Expand All @@ -9,7 +27,7 @@ const DEMO_CONFIG = {
}
};

describe('It tests a combination of Cloudianry URL and Configuration', () => {
describe('It tests a combination of Cloudinary URL and Configuration', () => {
it ('Generates a URL', () => {
const url = new TransformableImage('my_image')
.setConfig(DEMO_CONFIG)
Expand Down Expand Up @@ -74,4 +92,58 @@ describe('It tests a combination of Cloudianry URL and Configuration', () => {

expect(url).toBe('https://res.cloudinary.com/MY_CLOUD_NAME/avatar/fetch/c_fill,h_100,w_100/sample');
});



it('Secure by default', () => {
const url = createURLFromConfig({});
expect(url).toContain('https://res.cloudinary.com/demo');
});

it('Supports secure:false', () => {
const url = createURLFromConfig({
secure:false
});
expect(url).toContain('http://res.cloudinary.com/demo');
});

it('Support cname with secure false', () => {
const url = createURLFromConfig({
cname:'hello.com',
secure: false
});
expect(url).toContain('http://hello.com/demo');
});

it('Support secureDistribution with secure true', () => {
const url = createURLFromConfig({
secureDistribution:'foobar.com'
});
expect(url).toContain('https://foobar.com/demo');
});

it('Support private CDN with secure true', () => {
const url = createURLFromConfig({
privateCdn:true
});
expect(url).toContain(`https://demo-res.cloudinary.com/image/upload`);
});

it('Support secureDistribution with secure true', () => {
const url = createURLFromConfig({
secure: true,
privateCdn: true,
secureDistribution: "something.cloudfront.net"
});
expect(url).toContain('https://something.cloudfront.net/image/upload/');
});
});


/**
* http://res.cloudinary.com/{cloudName}
* https://res.cloudinary.com/{cloudName}
* https://{cloudName}-res.cloudinary.com/
* http://{domain}
* https://{domain}
*/
2 changes: 1 addition & 1 deletion jest.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
["jest-html-reporters", {
"publicPath" : "./public/progress/",
"filename": "cloudinary-base-progress-report.html",
"pageTitle": "Cloudianry JS 2.0 Progress Report",
"pageTitle": "Cloudinary JS 2.0 Progress Report",
"logoImgPath": "./__DOC_RESOURCES__/cloudinary-logo.png",
"expand": true
}]
Expand Down
2 changes: 1 addition & 1 deletion src/config/CloudinaryConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class CloudinaryConfig {
public cloud: CloudConfig;
public url: URLConfig;

constructor(configurations: ICloudinaryConfigurations) {
constructor(configurations: ICloudinaryConfigurations = {}) {
this.cloud = new CloudConfig(configurations.cloud);
this.url = new URLConfig(configurations.url || {});
}
Expand Down
8 changes: 4 additions & 4 deletions src/config/URLConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import {ALLOWED_URL_CONFIG} from "../internalConstants";
import ICloudConfig from "../interfaces/Config/ICloudConfig";

class URLConfig extends Config implements IURLConfig {
cdnSubdomain?: boolean;
secureCdnSubdomain?: boolean;
cname?: string; // User subdomain (example.cloudinary.com)
secureDistribution?: boolean;
secureDistribution?: string;
privateCdn?: boolean;
signUrl?: boolean;
longUrlSignature?: boolean;
Expand All @@ -22,7 +20,9 @@ class URLConfig extends Config implements IURLConfig {
constructor(userURLConfig: IURLConfig | unknown) {
super();
const urlConfig = this.filterOutNonSupportedKeys(userURLConfig, ALLOWED_URL_CONFIG);
Object.assign(this, {secure: true}, urlConfig);
Object.assign(this, {
secure: true
}, urlConfig);
}

extend(userURLConfig: ICloudConfig | unknown): URLConfig {
Expand Down
50 changes: 40 additions & 10 deletions src/interfaces/Config/IURLConfig.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
/**
* @name ICloudinaryAssetConfigurations
* @description
* Defines the configuration needed for URL-related options when creating Cloudianry URL
*
* @prop {boolean} [cdnSubdomain]
* @prop {boolean} [secureCdnSubdomain]
* Defines the configuration needed for URL-related options when creating Cloudinary URL
* @prop {string} [cname]
* @prop {boolean} [secureDistribution]
* @prop {boolean} [privateCdn]
Expand All @@ -17,18 +14,51 @@
* @prop {boolean} [analytics]
*/
interface IURLConfig {
cdnSubdomain?: boolean;
secureCdnSubdomain?: boolean;
cname?: string; // User subdomain (example.cloudinary.com)
secureDistribution?: boolean;
/**
* Replace the asset domain when secure is false
* http://{cname}/{cloudName}/image/upload
*/
cname?: string;

/**
* Replace the asset domain when secure is true
* https://{cname}/{cloudName}/image/upload
*/
secureDistribution?: string;

/**
* When Cname or secureDistribution are provided (with secure accordingly),
* privateCdn removes the cloudName from the URL:
*
* https://{cname|secureDistribution}/image/upload
* instead of
* * https://{cname|secureDistribution}/{cloudName}image/upload
*
* When privateCdn is provided without cname or secure distribution,
* it moves the cloudName from the URL to the domain:
*
* https://{cloudName}-res.cloudinary.com/image/upload
* instead of
* https://res.cloudinary.com/{cloudName}/image/upload
*/
privateCdn?: boolean;

/**
* use HTTPS or HTTP
*/
secure?: boolean;


/**
* Whether or not to include the SDK version signature in the URL
*/
analytics?: boolean;

signUrl?: boolean;
longUrlSignature?: boolean;
shorten?: boolean;
useRootPath?: boolean;
secure?: boolean;
forceVersion?: boolean;
analytics?: boolean;
}

export default IURLConfig;
2 changes: 0 additions & 2 deletions src/internalConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
* @private
*/
export const ALLOWED_URL_CONFIG = [
'cdnSubdomain',
'secureCdnSubdomain',
'cname',
'secureDistribution',
'privateCdn',
Expand Down
56 changes: 43 additions & 13 deletions src/url/cloudinaryURL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import ICloudinaryConfigurations from "../interfaces/Config/ICloudinaryConfigura
* @param {Object} config
* @param {Object} descriptor
* @param {Transformation} transformation
* @return {string} CloudianryURL
* @return {string} CloudinaryURL
*/
function createCloudinaryURL(config: ICloudinaryConfigurations, descriptor?: IDescriptor, transformation?: Transformation): string {
const prefix = getUrlPrefix(config.cloud.cloudName, config.url);
Expand All @@ -33,19 +33,49 @@ function createCloudinaryURL(config: ICloudinaryConfigurations, descriptor?: IDe

/**
* Create the URL prefix for Cloudinary resources.
* Available use cases
* http://res.cloudinary.com/{cloudName}
* https://res.cloudinary.com/{cloudName}
* https://{cloudName}-res.cloudinary.com/
* http://{domain}/${cloudName}
* https://{domain}/${cloudName}
* https://{domain}
* @private
*
* @param {string} cloudName
* @param {IURLConfig} urlConfig
*/
function getUrlPrefix(cloudName: string, urlConfig:IURLConfig) {
// defaults
const protocol = urlConfig.secure ? "https://" : "http://";
const cdnPart = "";
const subdomain = "res";
const host = ".cloudinary.com";
const path = `/${cloudName}`;

return [protocol, cdnPart, subdomain, host, path].join("");
function getUrlPrefix(cloudName: string, urlConfig: IURLConfig) {
const secure = urlConfig.secure;
const privateCDN = urlConfig.privateCdn;
const cname = urlConfig.cname;
const secureDistribution = urlConfig.secureDistribution;

if (!secure && !cname) {
return `http://res.cloudinary.com/${cloudName}`;
}

if (secure && !secureDistribution && privateCDN) {
return `https://${cloudName}-res.cloudinary.com`;
}

if (secure && !secureDistribution) {
return `https://res.cloudinary.com/${cloudName}`;
}

if (secure && secureDistribution && privateCDN) {
return `https://${secureDistribution}`;
}

if (secure && secureDistribution) {
return `https://${secureDistribution}/${cloudName}`;
}

if (!secure && cname) {
return `http://${cname}/${cloudName}`;
} else {
return 'ERROR';
}
}

/**
Expand All @@ -54,7 +84,7 @@ function getUrlPrefix(cloudName: string, urlConfig:IURLConfig) {
*/
function handleAssetType(descriptor: IDescriptor) {
//default to image
if(!descriptor || !descriptor.assetType) {
if (!descriptor || !descriptor.assetType) {
return 'image';
}

Expand All @@ -67,7 +97,7 @@ function handleAssetType(descriptor: IDescriptor) {
*/
function handleStorageType(descriptor: IDescriptor) {
//default to upload
if(!descriptor || !descriptor.storageType) {
if (!descriptor || !descriptor.storageType) {
return 'upload';
}

Expand All @@ -78,7 +108,7 @@ function handleStorageType(descriptor: IDescriptor) {
* @private
* @param descriptor
*/
function getUrlVersion(urlConfig:IURLConfig, descriptor: IDescriptor) {
function getUrlVersion(urlConfig: IURLConfig, descriptor: IDescriptor) {
const shouldForceVersion = urlConfig.forceVersion !== false;

if (descriptor.version) {
Expand Down