|
@@ -1,26 +1,20 @@
|
|
|
|
|
|
|
|
import { execSync } from 'child_process';
|
|
import { execSync } from 'child_process';
|
|
|
-import fs from 'fs';
|
|
|
|
|
import path from 'path';
|
|
import path from 'path';
|
|
|
|
|
|
|
|
import mongoose from 'mongoose';
|
|
import mongoose from 'mongoose';
|
|
|
-import streamToPromise from 'stream-to-promise';
|
|
|
|
|
-import unzipper from 'unzipper';
|
|
|
|
|
|
|
|
|
|
import { GrowiPlugin, GrowiPluginMeta, GrowiPluginOrigin } from '~/interfaces/plugin';
|
|
import { GrowiPlugin, GrowiPluginMeta, GrowiPluginOrigin } from '~/interfaces/plugin';
|
|
|
import loggerFactory from '~/utils/logger';
|
|
import loggerFactory from '~/utils/logger';
|
|
|
import { resolveFromRoot } from '~/utils/project-dir-utils';
|
|
import { resolveFromRoot } from '~/utils/project-dir-utils';
|
|
|
|
|
|
|
|
-
|
|
|
|
|
// eslint-disable-next-line import/no-cycle
|
|
// eslint-disable-next-line import/no-cycle
|
|
|
import Crowi from '../crowi';
|
|
import Crowi from '../crowi';
|
|
|
|
|
|
|
|
-
|
|
|
|
|
const logger = loggerFactory('growi:plugins:plugin-utils');
|
|
const logger = loggerFactory('growi:plugins:plugin-utils');
|
|
|
|
|
|
|
|
const pluginStoringPath = resolveFromRoot('tmp/plugins');
|
|
const pluginStoringPath = resolveFromRoot('tmp/plugins');
|
|
|
|
|
|
|
|
-
|
|
|
|
|
export class PluginService {
|
|
export class PluginService {
|
|
|
|
|
|
|
|
crowi: any;
|
|
crowi: any;
|
|
@@ -46,7 +40,7 @@ export class PluginService {
|
|
|
await this.downloadZipFile(`${ghUrl}/archive/refs/heads/master.zip`, downloadDir);
|
|
await this.downloadZipFile(`${ghUrl}/archive/refs/heads/master.zip`, downloadDir);
|
|
|
}
|
|
}
|
|
|
catch (err) {
|
|
catch (err) {
|
|
|
- // TODO: error handling
|
|
|
|
|
|
|
+ console.log('downloadZipFile error', err);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// TODO: detect plugins
|
|
// TODO: detect plugins
|
|
@@ -129,87 +123,17 @@ export class PluginService {
|
|
|
return [plugin];
|
|
return [plugin];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
async listPlugins(): Promise<GrowiPlugin[]> {
|
|
async listPlugins(): Promise<GrowiPlugin[]> {
|
|
|
return [];
|
|
return [];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- sleep(waitMsec) {
|
|
|
|
|
- const startMsec = new Date();
|
|
|
|
|
-
|
|
|
|
|
- while (new Date() - startMsec < waitMsec);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
async downloadZipFile(ghUrl: string, filePath:string): Promise<void> {
|
|
async downloadZipFile(ghUrl: string, filePath:string): Promise<void> {
|
|
|
|
|
|
|
|
- console.log(`rm ${filePath}master.zip`);
|
|
|
|
|
-
|
|
|
|
|
const stdout1 = execSync(`wget ${ghUrl} -O ${filePath}master.zip`);
|
|
const stdout1 = execSync(`wget ${ghUrl} -O ${filePath}master.zip`);
|
|
|
- console.log(`wget ${ghUrl} -O ${filePath}master.zip`);
|
|
|
|
|
- console.log(`unzip ${filePath}master.zip -d ${filePath}`);
|
|
|
|
|
- this.sleep(5000);
|
|
|
|
|
const stdout2 = execSync(`unzip ${filePath}master.zip -d ${filePath}`);
|
|
const stdout2 = execSync(`unzip ${filePath}master.zip -d ${filePath}`);
|
|
|
- console.log(`unzip ${filePath}master.zip -d ${filePath}`);
|
|
|
|
|
const stdout3 = execSync(`rm ${filePath}master.zip`);
|
|
const stdout3 = execSync(`rm ${filePath}master.zip`);
|
|
|
|
|
|
|
|
- // try {
|
|
|
|
|
- // const zipFile = await this.getFile('master.zip');
|
|
|
|
|
-
|
|
|
|
|
- // // await this.unzip('/workspace/growi/packages/app/tmp/plugins/master.zip');
|
|
|
|
|
-
|
|
|
|
|
- // }
|
|
|
|
|
- // catch (err) {
|
|
|
|
|
- // console.log(err);
|
|
|
|
|
- // }
|
|
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * extract a zip file
|
|
|
|
|
- *
|
|
|
|
|
- * @memberOf ImportService
|
|
|
|
|
- * @param {string} zipFile absolute path to zip file
|
|
|
|
|
- * @return {Array.<string>} array of absolute paths to extracted files
|
|
|
|
|
- */
|
|
|
|
|
- async unzip(zipFile) {
|
|
|
|
|
- // const stream = fs.createReadStream(zipFile).pipe(unzipper.Extract({ path: '/workspace/growi/packages/app/tmp/plugins/master' }));
|
|
|
|
|
- // try {
|
|
|
|
|
- // await streamToPromise(stream);
|
|
|
|
|
- // }
|
|
|
|
|
- // catch (err) {
|
|
|
|
|
- // console.log('err', err);
|
|
|
|
|
- // }
|
|
|
|
|
- const readStream = fs.createReadStream(zipFile);
|
|
|
|
|
- const unzipStream = readStream.pipe(unzipper.Parse());
|
|
|
|
|
- const files: any = [];
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- unzipStream.on('entry', async(entry) => {
|
|
|
|
|
- const fileName = entry.path;
|
|
|
|
|
- // https://regex101.com/r/mD4eZs/6
|
|
|
|
|
- // prevent from unexpecting attack doing unzip file (path traversal attack)
|
|
|
|
|
- // FOR EXAMPLE
|
|
|
|
|
- // ../../src/server/views/admin/markdown.html
|
|
|
|
|
- if (fileName.match(/(\.\.\/|\.\.\\)/)) {
|
|
|
|
|
- logger.error('File path is not appropriate.', fileName);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (fileName === this.growiBridgeService.getMetaFileName()) {
|
|
|
|
|
- // skip meta.json
|
|
|
|
|
- entry.autodrain();
|
|
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
- const jsonFile = path.join(this.baseDir, fileName);
|
|
|
|
|
- const writeStream = fs.createWriteStream(jsonFile, { encoding: this.growiBridgeService.getEncoding() });
|
|
|
|
|
- entry.pipe(writeStream);
|
|
|
|
|
- files.push(jsonFile);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- await streamToPromise(unzipStream);
|
|
|
|
|
-
|
|
|
|
|
- return files;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
}
|
|
}
|