Skip to content

Commit 54a7204

Browse files
authored
Add GridStoreAdapter and FSAdapter Config (#778)
1 parent 501344c commit 54a7204

File tree

1 file changed

+182
-1
lines changed

1 file changed

+182
-1
lines changed

_includes/parse-server/file-adapters.md

Lines changed: 182 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,96 @@ Parse Server allows developers to choose from several options when hosting files
44

55
* `GridStoreAdapter`, which is backed by MongoDB;
66
* `S3Adapter`, which is backed by [Amazon S3](https://aws.amazon.com/s3/); or
7-
* `GCSAdapter`, which is backed by [Google Cloud Storage](https://cloud.google.com/storage/)
7+
* `GCSAdapter`, which is backed by [Google Cloud Storage](https://cloud.google.com/storage/); or
8+
* `FSAdapter`, local file storage
89

910
`GridStoreAdapter` is used by default and requires no setup, but if you're interested in using S3 or Google Cloud Storage, additional configuration information is available below.
1011

1112
When using files on Parse, you will need to use the `publicServerURL` option in your Parse Server config. This is the URL that files will be accessed from, so it should be a URL that resolves to your Parse Server. Make sure to include your mount point in this URL.
1213

14+
When using `Postgres`, you will need to configure `S3Adapter`, `GCSAdapter`, or `FSAdapter` for file support. The `GridStoreAdapter` does not work with `Postgres`.
15+
16+
## Configuring `GridStoreAdapter`
17+
18+
If you are using `Mongo` and don't need file encryption, there are no additional steps needed to use the `GridStoreAdapter`. If you'd like to enable file encryption follow these instructions to configure Parse Server to use `GridStoreAdapter` with file encryption.
19+
20+
***Notice: If you are coming from an older version of Parse Server versions <= 4.2.0, you should remove `fileKey` from your configurations as it is not being used anyways since legacy parse.com. `fileKey` has been repurposed for file encryption.***
21+
22+
### Set up file encryption (available in parse-server 4.3.0+)
23+
The `GridStoreAdapter` can encrypt files at rest in `Mongo` using AES256-GCM, allowing the adapter to detect if files are tampered with.
24+
25+
To use, simply do any of the following:
26+
- Use the environment variable `PARSE_SERVER_FILE_KEY`
27+
- Pass in --fileKey in the command line when starting your server
28+
- Initialize ParseServer with `fileKey="Your file encryptionKey"`.
29+
30+
An example starting your Parse Server in `index.js` is below:
31+
32+
```javascript
33+
const api = new ParseServer({
34+
databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
35+
cloud: process.env.PARSE_SERVER_CLOUD || __dirname + '/cloud/main.js',
36+
appId: process.env.PARSE_SERVER_APPLICATION_ID || 'myAppId',
37+
masterKey: process.env.PARSE_SERVER_MASTER_KEY || '',
38+
fileKey: process.env.PARSE_SERVER_FILE_KEY, //Add your file key here. Keep it secret
39+
...
40+
});
41+
```
42+
43+
Be sure not to lose your key or change it after encrypting files.
44+
45+
### Enabling encryption on a server that already has unencrypted files (available in parse-server 4.4.0+)
46+
When this is the case, it is recommended to start up a development parse-server (or a separate process from your main process) that has the same configuration as your production server. On the development server, initialize the file adapter as above with the new key and do the following after initialization in your `index.js`:
47+
48+
```javascript
49+
//You probably want to back up your unencrypted files before doing this.
50+
//This can take awhile depending on how many files and how large they are. It will attempt to rotate the key of all files in your filesSubDirectory
51+
const {rotated, notRotated} = await api.filesAdapter.rotateFileKey();
52+
console.log('Files rotated to newKey: ' + rotated);
53+
console.log('Files that couldn't be rotated to newKey: ' + notRotated);
54+
```
55+
56+
### Rotating your encryption key (available in parse-server 4.4.0+)
57+
Periodically you may want to rotate your fileKey for security reasons. When this is the case, it is recommended to start up a development parse-server (or a separate process from your main process) that has the same configuration as your production server. On the development server, initialize the file adapter with the new key and do the following in your `index.js` (you will need your `oldKey`):
58+
59+
```javascript
60+
//This can take awhile depending on how many files and how large they are. It will attempt to rotate the key of all files in your filesSubDirectory
61+
const {rotated, notRotated} = await api.filesAdapter.rotateFileKey({oldKey: oldKey});
62+
console.log('Files rotated to newKey: ' + rotated);
63+
console.log('Files that couldn't be rotated to newKey: ' + notRotated);
64+
```
65+
66+
### Removing file encryption (available in parse-server 4.4.0+)
67+
When this is the case, it is recommended to start up a development parse-server (or a separate process from your main process) that has the same configuration as your production server. Different from the previous examples, don't initialize your fileAdapter with a `fileKey`. Pass in your `oldKey` to `rotateFileKey()`.
68+
69+
```javascript
70+
const api = new ParseServer({
71+
databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
72+
cloud: process.env.PARSE_SERVER_CLOUD || __dirname + '/cloud/main.js',
73+
appId: process.env.PARSE_SERVER_APPLICATION_ID || 'myAppId',
74+
masterKey: process.env.PARSE_SERVER_MASTER_KEY || '',
75+
//No fileKey here
76+
...
77+
});
78+
79+
//This can take awhile depending on how many files and how larger they are. It will attempt to rotate the key of all files in your filesSubDirectory
80+
//It is not recommended to do this on the production server, deploy a development server to complete the process.
81+
const {rotated, notRotated} = await api.filesAdapter.rotateFileKey({oldKey: oldKey});
82+
console.log('Files rotated to unencrypted with noKey: ' + rotated);
83+
console.log('Files that couldn't be rotated to unencrypted with noKey: ' + notRotated);
84+
85+
```
86+
87+
### Rotating the key for a subset of files
88+
This is useful if for some reason there were errors and some of the files weren't rotated and returned in `notRotated`. The process is the same as the previous examples, but pass in your `oldKey` along with the array of `fileNames` to `rotateFileKey()`.
89+
90+
```javascript
91+
//This can take awhile depending on how many files and how large they are. It will attempt to rotate the key of all files in your filesSubDirectory
92+
const {rotated, notRotated} = await api.filesAdapter.rotateFileKey({oldKey: oldKey, fileNames: ["fileName1.png","fileName2.png"]});
93+
console.log('Files rotated to newKey: ' + rotated);
94+
console.log('Files that couldn't be rotated to newKey: ' + notRotated);
95+
```
96+
1397
## Configuring `S3Adapter`
1498

1599
If you'd like to use Amazon S3, follow these instructions to configure Parse Server to use `S3Adapter`.
@@ -221,3 +305,100 @@ new GCSAdapter(projectId, keyfilePath, bucket, options)
221305
| options | JavaScript object (map) that can contain: | |
222306
| bucketPrefix | Key in `options`. Set to create all the files with the specified prefix added to the filename. Can be used to put all the files for an app in a folder with 'folder/'. | Optional. Default: '' |
223307
| directAccess | Key in `options`. Controls whether reads are going directly to GCS or proxied through your Parse Server. | Optional. Default: false |
308+
309+
## Configuring `FSAdapter`
310+
311+
To use the `FSAdapter`, simply initialize your Parse Server in `index.js` by doing the following:
312+
313+
```javascript
314+
var FSFilesAdapter = require('@parse/fs-files-adapter');
315+
316+
var fsAdapter = new FSFilesAdapter({
317+
"filesSubDirectory": "my/files/folder" // optional
318+
});
319+
320+
var api = new ParseServer({
321+
appId: 'my_app',
322+
masterKey: 'master_key',
323+
filesAdapter: fsAdapter
324+
})
325+
```
326+
327+
***Notice: If used with Parse Server versions <= 4.2.0, DO NOT PASS in `PARSE_SERVER_FILE_KEY` or `fileKey` from parse-server. Instead pass your key directly to `FSFilesAdapter` using your own environment variable or hardcoding the string. Parse Server versions 4.3.0+ can pass in `PARSE_SERVER_FILE_KEY` or `fileKey`.***
328+
329+
### Using `FSAdapter` with multiple instances of Parse Server
330+
When using parse-server-fs-adapter across multiple Parse Server instances it's important to establish "centralization" of your file storage (this is the same premise as the other file adapters, you are sending/recieving files through a dedicated link). You can accomplish this at the file storage level by Samba mounting (or any other type of mounting) your storage to each of your parse-server instances, e.g if you are using Parse Server via docker (volume mount your SMB drive to `- /Volumes/SMB-Drive/MyParseApp1/files:/parse-server/files`). All Parse Server instances need to be able to read/write to the same storage in order for parse-server-fs-adapter to work properly with parse-server. If the file storage isn't centralized, parse-server will have trouble locating files and you will get random behavior on client-side.
331+
332+
### Set up file encryption (available in parse-server-fs-adapter 1.1.0+)
333+
The `FSAdapter` can encrypt files at rest for local storage using AES256-GCM, allowing the adapter to detect if files are tampered with.
334+
335+
To use, simply do the same as above, but add a `fileKey`:
336+
337+
```javascript
338+
var FSFilesAdapter = require('@parse/fs-files-adapter');
339+
340+
var fsAdapter = new FSFilesAdapter({
341+
"filesSubDirectory": "my/files/folder", // optional
342+
"fileKey": "someKey" //mandatory if you want to encrypt files
343+
});
344+
345+
var api = new ParseServer({
346+
appId: 'my_app',
347+
masterKey: 'master_key',
348+
filesAdapter: fsAdapter
349+
})
350+
```
351+
352+
Be sure not to lose your key or change it after encrypting files.
353+
354+
### Enabling encryption on a server that already has unencrypted files (available in parse-server-fs-adapter 1.1.0+)
355+
When this is the case, it is recommended to start up a development parse-server (or a separate process from your main process) that has the same configuration as your production server. On the development server, initialize the file adapter as above with the new key and do the following after initialization in your `index.js`:
356+
357+
```javascript
358+
//You probably want to back up your unencrypted files before doing this.
359+
//This can take awhile depending on how many files and how large they are. It will attempt to rotate the key of all files in your filesSubDirectory
360+
const {rotated, notRotated} = await api.filesAdapter.rotateFileKey();
361+
console.log('Files rotated to newKey: ' + rotated);
362+
console.log('Files that couldn't be rotated to newKey: ' + notRotated);
363+
```
364+
365+
### Rotating your encryption key (available in parse-server-fs-adapter 1.1.0+)
366+
Periodically you may want to rotate your `fileKey` for security reasons. When this is the case, it is recommended to start up a development parse-server (or a separate process from your main process) that has the same configuration as your production server. On the development server, initialize the file adapter with the new key and do the following in your `index.js` (you will need your `oldKey`):
367+
368+
```javascript
369+
//This can take awhile depending on how many files and how large they are. It will attempt to rotate the key of all files in your filesSubDirectory
370+
const {rotated, notRotated} = await api.filesAdapter.rotateFileKey({oldKey: oldKey});
371+
console.log('Files rotated to newKey: ' + rotated);
372+
console.log('Files that couldn't be rotated to newKey: ' + notRotated);
373+
```
374+
375+
### Removing file encryption (available in parse-server-fs-adapter 1.1.0+)
376+
When this is the case, it is recommended to start up a development parse-server (or a separate process from your main process) that has the same configuration as your production server. Different from the previous examples, don't initialize your fileAdapter with a `fileKey`. Pass in your `oldKey` to `rotateFileKey()`.
377+
378+
```javascript
379+
const api = new ParseServer({
380+
databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
381+
cloud: process.env.PARSE_SERVER_CLOUD || __dirname + '/cloud/main.js',
382+
appId: process.env.PARSE_SERVER_APPLICATION_ID || 'myAppId',
383+
masterKey: process.env.PARSE_SERVER_MASTER_KEY || '',
384+
filesAdapter: new FSFilesAdapter(), //No fileKey supplied
385+
...
386+
});
387+
388+
//This can take awhile depending on how many files and how larger they are. It will attempt to rotate the key of all files in your filesSubDirectory
389+
//It is not recommended to do this on the production server, deploy a development server to complete the process.
390+
const {rotated, notRotated} = await api.filesAdapter.rotateFileKey({oldKey: oldKey});
391+
console.log('Files rotated to unencrypted with noKey: ' + rotated);
392+
console.log('Files that couldn't be rotated to unencrypted with noKey: ' + notRotated);
393+
394+
```
395+
396+
### Rotating the key for a subset of files
397+
This is useful if for some reason there were errors and some of the files weren't rotated and returned in `notRotated`. The process is the same as the previous examples, but pass in your `oldKey` along with the array of `fileNames` to `rotateFileKey()`.
398+
399+
```javascript
400+
//This can take awhile depending on how many files and how large they are. It will attempt to rotate the key of all files in your filesSubDirectory
401+
const {rotated, notRotated} = await api.filesAdapter.rotateFileKey({oldKey: oldKey, fileNames: ["fileName1.png","fileName2.png"]});
402+
console.log('Files rotated to newKey: ' + rotated);
403+
console.log('Files that couldn't be rotated to newKey: ' + notRotated);
404+
```

0 commit comments

Comments
 (0)