@unchainedshop/file-upload 1.1.4 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/license +274 -0
- package/package.json +9 -7
- package/tests/file-upload-index.test.ts +1 -1
- package/tsconfig.build.json +12 -4
- package/.npm/package/README +0 -7
- package/.npm/package/npm-shrinkwrap.json +0 -351
- package/.versions +0 -53
- package/lib/plugins/gridfs/gridfs-adapter.d.ts +0 -2
- package/lib/plugins/gridfs/gridfs-adapter.js +0 -108
- package/lib/plugins/gridfs/gridfs-adapter.js.map +0 -1
- package/lib/plugins/gridfs/gridfs-webhook.d.ts +0 -1
- package/lib/plugins/gridfs/gridfs-webhook.js +0 -54
- package/lib/plugins/gridfs/gridfs-webhook.js.map +0 -1
- package/lib/plugins/gridfs/index.d.ts +0 -8
- package/lib/plugins/gridfs/index.js +0 -21
- package/lib/plugins/gridfs/index.js.map +0 -1
- package/lib/plugins/gridfs/promisePipe.d.ts +0 -2
- package/lib/plugins/gridfs/promisePipe.js +0 -21
- package/lib/plugins/gridfs/promisePipe.js.map +0 -1
- package/lib/plugins/gridfs/sign.d.ts +0 -2
- package/lib/plugins/gridfs/sign.js +0 -12
- package/lib/plugins/gridfs/sign.js.map +0 -1
- package/lib/plugins/minio-adapter.d.ts +0 -4
- package/lib/plugins/minio-adapter.js +0 -167
- package/lib/plugins/minio-adapter.js.map +0 -1
- package/lib/plugins/minio-webhook.d.ts +0 -1
- package/lib/plugins/minio-webhook.js +0 -45
- package/lib/plugins/minio-webhook.js.map +0 -1
- package/package.js +0 -34
- package/src/plugins/gridfs/gridfs-adapter.ts +0 -137
- package/src/plugins/gridfs/gridfs-webhook.js +0 -60
- package/src/plugins/gridfs/index.js +0 -21
- package/src/plugins/gridfs/promisePipe.js +0 -19
- package/src/plugins/gridfs/sign.js +0 -16
- package/src/plugins/minio-adapter.ts +0 -216
- package/src/plugins/minio-webhook.js +0 -51
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { IFileAdapter } from '@unchainedshop/types/files';
|
|
2
|
-
import { FileAdapter } from '../director/FileAdapter';
|
|
3
|
-
import { FileDirector } from '../director/FileDirector';
|
|
4
|
-
|
|
5
|
-
import https from 'https';
|
|
6
|
-
import http, { OutgoingHttpHeaders } from 'http';
|
|
7
|
-
import { log, LogLevel } from '@unchainedshop/logger';
|
|
8
|
-
import mimeType from 'mime-types';
|
|
9
|
-
import Minio from 'minio';
|
|
10
|
-
import { Readable } from 'stream';
|
|
11
|
-
import { URL } from 'url';
|
|
12
|
-
import buildHashedFilename from '../buildHashedFilename';
|
|
13
|
-
|
|
14
|
-
const {
|
|
15
|
-
MINIO_ACCESS_KEY,
|
|
16
|
-
MINIO_REGION,
|
|
17
|
-
MINIO_SECRET_KEY,
|
|
18
|
-
MINIO_ENDPOINT,
|
|
19
|
-
MINIO_BUCKET_NAME,
|
|
20
|
-
NODE_ENV,
|
|
21
|
-
AMAZON_S3_SESSION_TOKEN,
|
|
22
|
-
} = process.env;
|
|
23
|
-
const PUT_URL_EXPIRY = 24 * 60 * 60;
|
|
24
|
-
|
|
25
|
-
let client: Minio.Client;
|
|
26
|
-
|
|
27
|
-
export async function connectToMinio(credentialsProvider) {
|
|
28
|
-
if (!MINIO_ENDPOINT || !MINIO_BUCKET_NAME) {
|
|
29
|
-
log(
|
|
30
|
-
'Please configure Minio/S3 by providing MINIO_ENDPOINT & MINIO_BUCKET_NAME to use upload features',
|
|
31
|
-
{ level: LogLevel.Error },
|
|
32
|
-
);
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
try {
|
|
37
|
-
const resolvedUrl = new URL(MINIO_ENDPOINT);
|
|
38
|
-
const minioClient = new Minio.Client({
|
|
39
|
-
endPoint: resolvedUrl.hostname,
|
|
40
|
-
useSSL: resolvedUrl.protocol === 'https:',
|
|
41
|
-
port: parseInt(resolvedUrl.port, 10) || undefined,
|
|
42
|
-
region: MINIO_REGION,
|
|
43
|
-
sessionToken: AMAZON_S3_SESSION_TOKEN,
|
|
44
|
-
accessKey: MINIO_ACCESS_KEY,
|
|
45
|
-
secretKey: MINIO_SECRET_KEY,
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
if (NODE_ENV === 'development') minioClient?.traceOn(process.stdout);
|
|
49
|
-
|
|
50
|
-
if (credentialsProvider) {
|
|
51
|
-
await minioClient.setCredentialsProvider(credentialsProvider);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
client = minioClient;
|
|
55
|
-
} catch (error) {
|
|
56
|
-
log(`Exception while creating Minio client: ${error.message}`, {
|
|
57
|
-
level: LogLevel.Error,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const generateMinioUrl = (directoryName: string, hashedFilename: string) => {
|
|
64
|
-
return `${MINIO_ENDPOINT}/${MINIO_BUCKET_NAME}/${directoryName}/${hashedFilename}`;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const getMimeType = (extension) => {
|
|
68
|
-
return mimeType.lookup(extension);
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
connectToMinio().then((c) => {
|
|
72
|
-
client = c;
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const createDownloadStream = (
|
|
76
|
-
fileUrl: string,
|
|
77
|
-
headers: OutgoingHttpHeaders,
|
|
78
|
-
): Promise<http.IncomingMessage> => {
|
|
79
|
-
const { href, protocol } = new URL(fileUrl);
|
|
80
|
-
return new Promise((resolve, reject) => {
|
|
81
|
-
try {
|
|
82
|
-
if (protocol === 'http:') {
|
|
83
|
-
http.get(href, { headers }, resolve);
|
|
84
|
-
} else {
|
|
85
|
-
https.get(href, { headers }, resolve);
|
|
86
|
-
}
|
|
87
|
-
} catch (e) {
|
|
88
|
-
reject(e);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const getObjectStats = async (fileName: string) => {
|
|
94
|
-
if (!client) throw new Error('Minio not connected, check env variables');
|
|
95
|
-
|
|
96
|
-
return client.statObject(MINIO_BUCKET_NAME, fileName);
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const bufferToStream = (buffer: any) => {
|
|
100
|
-
const stream = new Readable();
|
|
101
|
-
stream.push(buffer);
|
|
102
|
-
stream.push(null);
|
|
103
|
-
|
|
104
|
-
return stream;
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const getExpiryDate = () => new Date(new Date().getTime() + PUT_URL_EXPIRY);
|
|
108
|
-
|
|
109
|
-
export const MinioAdapter: IFileAdapter = {
|
|
110
|
-
key: 'shop.unchained.file-upload-plugin.minio',
|
|
111
|
-
label: 'Uploads files into an S3 bucket using minio',
|
|
112
|
-
version: '1.0',
|
|
113
|
-
|
|
114
|
-
...FileAdapter,
|
|
115
|
-
|
|
116
|
-
async createSignedURL(directoryName, fileName) {
|
|
117
|
-
if (!client) throw new Error('Minio not connected, check env variables');
|
|
118
|
-
|
|
119
|
-
const expiryDate = getExpiryDate();
|
|
120
|
-
const _id = buildHashedFilename(directoryName, fileName, expiryDate);
|
|
121
|
-
|
|
122
|
-
const url = await client.presignedPutObject(
|
|
123
|
-
MINIO_BUCKET_NAME,
|
|
124
|
-
`${directoryName}/${_id}`,
|
|
125
|
-
PUT_URL_EXPIRY,
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
return {
|
|
129
|
-
_id,
|
|
130
|
-
directoryName,
|
|
131
|
-
expiryDate,
|
|
132
|
-
fileName,
|
|
133
|
-
type: getMimeType(fileName),
|
|
134
|
-
putURL: url,
|
|
135
|
-
url: generateMinioUrl(directoryName, _id),
|
|
136
|
-
};
|
|
137
|
-
},
|
|
138
|
-
|
|
139
|
-
async removeFiles(files) {
|
|
140
|
-
if (!client) throw new Error('Minio not connected, check env variables');
|
|
141
|
-
|
|
142
|
-
const fileIds = files.map(({ path, _id }) => {
|
|
143
|
-
return `${path}/${_id}`;
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
await client.removeObjects(MINIO_BUCKET_NAME, fileIds);
|
|
147
|
-
},
|
|
148
|
-
|
|
149
|
-
async uploadFileFromStream(directoryName: string, rawFile: any) {
|
|
150
|
-
if (!client) throw new Error('Minio not connected, check env variables');
|
|
151
|
-
|
|
152
|
-
let stream;
|
|
153
|
-
let fileName;
|
|
154
|
-
if (rawFile instanceof Promise) {
|
|
155
|
-
const { filename: fname, createReadStream } = await rawFile;
|
|
156
|
-
fileName = fname;
|
|
157
|
-
stream = createReadStream();
|
|
158
|
-
} else {
|
|
159
|
-
fileName = rawFile.filename;
|
|
160
|
-
stream = bufferToStream(Buffer.from(rawFile.buffer, 'base64'));
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const _id = buildHashedFilename(directoryName, fileName, new Date());
|
|
164
|
-
const type = rawFile?.mimetype || getMimeType(fileName);
|
|
165
|
-
|
|
166
|
-
const metaData = {
|
|
167
|
-
'Content-Type': type,
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
await client.putObject(MINIO_BUCKET_NAME, `${directoryName}/${_id}`, stream, undefined, metaData);
|
|
171
|
-
|
|
172
|
-
const { size } = await getObjectStats(`${directoryName}/${_id}`);
|
|
173
|
-
|
|
174
|
-
return {
|
|
175
|
-
_id,
|
|
176
|
-
directoryName,
|
|
177
|
-
expiryDate: null,
|
|
178
|
-
fileName,
|
|
179
|
-
size,
|
|
180
|
-
type,
|
|
181
|
-
url: generateMinioUrl(directoryName, _id),
|
|
182
|
-
};
|
|
183
|
-
},
|
|
184
|
-
|
|
185
|
-
async uploadFileFromURL(directoryName: string, { fileLink, fileName: fname, headers }: any) {
|
|
186
|
-
if (!client) throw new Error('Minio not connected, check env variables');
|
|
187
|
-
|
|
188
|
-
const { href } = new URL(fileLink);
|
|
189
|
-
const fileName = fname || href.split('/').pop();
|
|
190
|
-
const _id = buildHashedFilename(directoryName, fileName, new Date());
|
|
191
|
-
|
|
192
|
-
const stream = await createDownloadStream(fileLink, headers);
|
|
193
|
-
const type = stream?.headers?.['content-type'] || getMimeType(fileName);
|
|
194
|
-
|
|
195
|
-
const metaData = {
|
|
196
|
-
'Content-Type': type,
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
await client.putObject(MINIO_BUCKET_NAME, `${directoryName}/${_id}`, stream, undefined, metaData);
|
|
200
|
-
const { size } = await getObjectStats(`${directoryName}/${_id}`);
|
|
201
|
-
|
|
202
|
-
return {
|
|
203
|
-
_id,
|
|
204
|
-
directoryName,
|
|
205
|
-
expiryDate: null,
|
|
206
|
-
fileName,
|
|
207
|
-
size,
|
|
208
|
-
type,
|
|
209
|
-
url: generateMinioUrl(directoryName, _id),
|
|
210
|
-
};
|
|
211
|
-
},
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
FileDirector.registerAdapter(MinioAdapter);
|
|
215
|
-
|
|
216
|
-
export default MinioAdapter;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { useMiddlewareWithCurrentContext } from 'meteor/unchained:api';
|
|
2
|
-
import { log, LogLevel } from '@unchainedshop/logger';
|
|
3
|
-
import bodyParser from 'body-parser';
|
|
4
|
-
|
|
5
|
-
const { MINIO_WEBHOOK_AUTH_TOKEN } = process.env;
|
|
6
|
-
|
|
7
|
-
const isAuthorized = ({ authorization = '' }) => {
|
|
8
|
-
const [type, token] = authorization.split(' ');
|
|
9
|
-
return type === 'Bearer' && token === MINIO_WEBHOOK_AUTH_TOKEN;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
useMiddlewareWithCurrentContext(
|
|
13
|
-
'/minio/',
|
|
14
|
-
bodyParser.json({
|
|
15
|
-
strict: false,
|
|
16
|
-
}),
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
useMiddlewareWithCurrentContext('/minio/', async (req, res) => {
|
|
20
|
-
try {
|
|
21
|
-
if (req.method === 'POST' && req.body) {
|
|
22
|
-
const { headers } = req;
|
|
23
|
-
const { Records = [], EventName } = req.body;
|
|
24
|
-
if (EventName === 's3:ObjectCreated:Put' && isAuthorized(headers)) {
|
|
25
|
-
const [{ s3 }] = Records;
|
|
26
|
-
const { object } = s3;
|
|
27
|
-
const { size, contentType: type } = object;
|
|
28
|
-
const [fileId] = object.key.split('.');
|
|
29
|
-
const { services } = req.unchainedContext;
|
|
30
|
-
await services.files.linkFile({ fileId, type, size }, req.unchainedContext);
|
|
31
|
-
res.writeHead(200);
|
|
32
|
-
res.end();
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
res.writeHead(404);
|
|
37
|
-
res.end();
|
|
38
|
-
return;
|
|
39
|
-
} catch (e) {
|
|
40
|
-
log(e.message, { level: LogLevel.Error });
|
|
41
|
-
res.writeHead(503);
|
|
42
|
-
res.end(JSON.stringify(e));
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
/*
|
|
47
|
-
|
|
48
|
-
curl -X PUT -T /Users/pozylon/Desktop/Bildschirmfoto\ 2022-02-17\ um\ 16.47.22.png http://localhost:4010/gridfs/3e0cd78ac07f0028890ce36c391057dd0c5fb46f4c147fb73e54bd8a7ffee389/user-avatars/avatar.png?e=1645883865878&s=e7466b30039593e5790e23cab92878e0144289c3710344a55b78c9a916e2f78c
|
|
49
|
-
curl -X PUT -T /Users/pozylon/Desktop/Bildschirmfoto\ 2022-02-17\ um\ 16.47.22.png https://minio.dev.shared.ucc.dev/unchained-test-bucket/user-avatars/9aedd551499b2850e9483b07cd4c8cff7ad1d710f49933c183861bf40183bc5a?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=unchained-test%2F20220225%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20220225T140957Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=22807026db1210370170cd5cf49bfbb9e86010425c9d1834a56e049faf39b368
|
|
50
|
-
|
|
51
|
-
*/
|