2020-02-07 07:04:18 +04:00
|
|
|
import joi from '@hapi/joi';
|
|
|
|
import { createHash } from 'crypto';
|
|
|
|
import { Request, Response } from 'express';
|
|
|
|
|
|
|
|
import { logger } from '../logger';
|
|
|
|
import latestSchema from '../schemas/share-latest';
|
|
|
|
import { storage } from '../storage';
|
|
|
|
|
|
|
|
interface ShareBody {
|
|
|
|
editor: {
|
|
|
|
language: string;
|
|
|
|
code: string;
|
2020-02-24 23:29:11 +04:00
|
|
|
dirty: boolean;
|
|
|
|
title: string;
|
2020-02-07 07:04:18 +04:00
|
|
|
};
|
|
|
|
compile: {
|
|
|
|
entrypoint: string;
|
|
|
|
};
|
|
|
|
dryRun: {
|
|
|
|
entrypoint: string;
|
|
|
|
parameters: string;
|
|
|
|
storage: string;
|
|
|
|
};
|
|
|
|
deploy: {
|
|
|
|
entrypoint: string;
|
|
|
|
storage: string;
|
|
|
|
useTezBridge?: boolean;
|
|
|
|
};
|
|
|
|
evaluateValue: {
|
|
|
|
entrypoint: string;
|
|
|
|
};
|
|
|
|
evaluateFunction: {
|
|
|
|
entrypoint: string;
|
|
|
|
parameters: string;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
const validateRequest = (body: any): { value: ShareBody; error: any } => {
|
|
|
|
return joi
|
|
|
|
.object({
|
|
|
|
editor: joi
|
|
|
|
.object({
|
|
|
|
language: joi.string().required(),
|
2020-02-24 23:29:11 +04:00
|
|
|
code: joi.string().required(),
|
|
|
|
dirty: joi.boolean().optional(),
|
|
|
|
title: joi.string().allow('')
|
2020-02-07 07:04:18 +04:00
|
|
|
})
|
|
|
|
.required(),
|
|
|
|
compile: joi.object({
|
|
|
|
entrypoint: joi.string().allow('')
|
|
|
|
}),
|
|
|
|
dryRun: joi.object({
|
|
|
|
entrypoint: joi.string().allow(''),
|
|
|
|
parameters: joi.any().allow(''),
|
|
|
|
storage: joi.any().allow('')
|
|
|
|
}),
|
|
|
|
deploy: joi.object({
|
|
|
|
entrypoint: joi.string().allow(''),
|
|
|
|
storage: joi.any().allow(''),
|
|
|
|
useTezBridge: joi.boolean().optional()
|
|
|
|
}),
|
|
|
|
evaluateValue: joi.object({
|
|
|
|
entrypoint: joi.string().allow('')
|
|
|
|
}),
|
|
|
|
evaluateFunction: joi.object({
|
|
|
|
entrypoint: joi.string().allow(''),
|
|
|
|
parameters: joi.any().allow('')
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.validate(body);
|
|
|
|
};
|
|
|
|
|
|
|
|
function escapeUrl(str: string) {
|
|
|
|
return str
|
|
|
|
.replace(/\+/g, '-')
|
|
|
|
.replace(/\//g, '_')
|
|
|
|
.replace(/=/g, '');
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function shareHandler(req: Request, res: Response) {
|
|
|
|
const { error, value } = validateRequest(req.body);
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
res.status(400).json({ error: error.message });
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
const versionedShareState = {
|
|
|
|
version: latestSchema.VERSION,
|
|
|
|
state: value
|
|
|
|
};
|
|
|
|
|
|
|
|
const { error } = latestSchema.validate(versionedShareState);
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
logger.error(
|
|
|
|
`${versionedShareState} doesn't match latest schema ${latestSchema.VERSION}`
|
|
|
|
);
|
|
|
|
res.sendStatus(500);
|
|
|
|
} else {
|
|
|
|
const fileContent = JSON.stringify(versionedShareState);
|
|
|
|
const hash = createHash('md5');
|
|
|
|
hash.update(fileContent);
|
|
|
|
const digest = escapeUrl(hash.digest('base64'));
|
|
|
|
const filename = `${digest}.txt`;
|
|
|
|
|
|
|
|
storage.write(filename, fileContent);
|
|
|
|
|
|
|
|
res.send({ hash: digest });
|
|
|
|
}
|
|
|
|
} catch (ex) {
|
|
|
|
logger.error(ex);
|
|
|
|
res.sendStatus(500);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|