2021-09-03 19:29:37 +03:00
|
|
|
const fs = require('fs-extra');
|
|
|
|
const os = require('os');
|
|
|
|
const path = require('path');
|
|
|
|
const security = require('@tryghost/security');
|
|
|
|
const request = require('@tryghost/request');
|
|
|
|
const errors = require('@tryghost/errors/lib/errors');
|
|
|
|
const limitService = require('../../services/limits');
|
|
|
|
const {setFromZip} = require('./storage');
|
|
|
|
|
2021-09-03 19:33:17 +03:00
|
|
|
const messages = {
|
|
|
|
repoDoesNotExist: 'Supplied GitHub theme does not exist or is inaccessible'
|
|
|
|
};
|
|
|
|
|
2021-09-03 19:29:37 +03:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {String} ref - theme reference in "Org/RepoName" format
|
|
|
|
* @returns {Promise<any>}
|
|
|
|
*/
|
|
|
|
const installFromGithub = async (ref) => {
|
|
|
|
const [org, repo] = ref.toLowerCase().split('/');
|
|
|
|
|
|
|
|
//TODO: move the organization check to config
|
|
|
|
if (limitService.isLimited('customThemes') && org.toLowerCase() !== 'tryghost') {
|
|
|
|
await limitService.errorIfWouldGoOverLimit('customThemes', {value: repo.toLowerCase()});
|
|
|
|
}
|
|
|
|
|
|
|
|
// omit /:ref so we fetch the default branch
|
|
|
|
const zipUrl = `https://api.github.com/repos/${org}/${repo}/zipball`;
|
|
|
|
const zipName = `${repo}.zip`;
|
|
|
|
|
|
|
|
// store zip in a unique temporary folder to avoid conflicts
|
|
|
|
const downloadBase = path.join(os.tmpdir(), security.identifier.uid(10));
|
|
|
|
const downloadPath = path.join(downloadBase, zipName);
|
|
|
|
|
|
|
|
await fs.ensureDir(downloadBase);
|
|
|
|
|
|
|
|
try {
|
|
|
|
// download zip file
|
|
|
|
const response = await request(zipUrl, {
|
|
|
|
followRedirect: true,
|
|
|
|
headers: {
|
|
|
|
accept: 'application/vnd.github.v3+json'
|
|
|
|
},
|
|
|
|
encoding: null
|
|
|
|
});
|
|
|
|
|
|
|
|
await fs.writeFile(downloadPath, response.body);
|
|
|
|
|
|
|
|
// install theme from zip
|
|
|
|
const zip = {
|
|
|
|
path: downloadPath,
|
|
|
|
name: zipName
|
|
|
|
};
|
|
|
|
const {theme, themeOverridden} = await setFromZip(zip);
|
|
|
|
|
|
|
|
return {theme, themeOverridden};
|
|
|
|
} catch (e) {
|
|
|
|
if (e.statusCode && e.statusCode === 404) {
|
|
|
|
return Promise.reject(new errors.BadRequestError({
|
2021-09-03 19:33:17 +03:00
|
|
|
message: messages.repoDoesNotExist,
|
2021-09-03 19:29:37 +03:00
|
|
|
context: zipUrl
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
throw e;
|
|
|
|
} finally {
|
|
|
|
// clean up tmp dir with downloaded file
|
|
|
|
fs.remove(downloadBase);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports.installFromGithub = installFromGithub;
|