Skip to content

Commit

Permalink
Merge pull request #790 from veliovgroup/dev
Browse files Browse the repository at this point in the history
v2.0.1

__New:__
- ✨ `config.disableSetTokenCookie` see #776 and #778 for details, thanks to @Kaczkazniszczenia

__Changed:__
- πŸ‘¨β€πŸ’» Abort http-fetch requests when calling `.abort()`;
- πŸ‘¨β€πŸ’» Make sure no other/delayed requests/responses executed;
  • Loading branch information
dr-dimitru authored Mar 1, 2021
2 parents 2b76cc3 + fff8e7a commit 7db9cfb
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 88 deletions.
37 changes: 23 additions & 14 deletions client.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import FilesCollectionCore from './core.js';
import { formatFleURL, helpers } from './lib.js';

const NOOP = () => { };
const allowedParams = ['debug', 'ddp', 'schema', 'public', 'chunkSize', 'downloadRoute', 'collection', 'collectionName', 'namingFunction', 'onBeforeUpload', 'allowClientCode', 'onbeforeunloadMessage', 'disableUpload', 'allowQueryStringCookies'];
const allowedParams = ['debug', 'ddp', 'schema', 'public', 'chunkSize', 'downloadRoute', 'collection', 'collectionName', 'namingFunction', 'onBeforeUpload', 'allowClientCode', 'onbeforeunloadMessage', 'disableUpload', 'disableSetTokenCookie', 'allowQueryStringCookies'];

/*
* @locus Anywhere
Expand All @@ -29,6 +29,7 @@ const allowedParams = ['debug', 'ddp', 'schema', 'public', 'chunkSize', 'downloa
* @param config.allowClientCode {Boolean} - [Both] Allow to run `remove` from client
* @param config.onbeforeunloadMessage {String|Function} - [Client] Message shown to user when closing browser's window or tab while upload process is running
* @param config.disableUpload {Boolean} - Disable file upload, useful for server only solutions
* @param config.disableSetTokenCookie {Boolean} - Disable cookie setting. Useful when you use multiple file collections or when you want to implement your own authorization.
* @param config.allowQueryStringCookies {Boolean} - Allow passing Cookies in a query string (in URL). Primary should be used only in Cordova environment. Note: this option will be used only on Cordova. Default: `false`
* @summary Create new instance of FilesCollection
*/
Expand Down Expand Up @@ -81,6 +82,10 @@ export class FilesCollection extends FilesCollectionCore {
this.disableUpload = false;
}

if (!helpers.isBoolean(this.disableSetTokenCookie)) {
this.disableSetTokenCookie = false;
}

if (!helpers.isString(this.downloadRoute)) {
this.downloadRoute = '/cdn/storage';
}
Expand All @@ -107,21 +112,25 @@ export class FilesCollection extends FilesCollectionCore {
this.onbeforeunloadMessage = 'Upload in a progress... Do you want to abort?';
}

const setTokenCookie = () => {
if (Meteor.connection._lastSessionId) {
cookie.set('x_mtok', Meteor.connection._lastSessionId, { path: '/', sameSite: 'Lax' });
if (Meteor.isCordova && this.allowQueryStringCookies) {
cookie.send();
if (!config.disableSetTokenCookie) {

const setTokenCookie = () => {
if (Meteor.connection._lastSessionId) {
cookie.set('x_mtok', Meteor.connection._lastSessionId, { path: '/', sameSite: 'Lax' });
if (Meteor.isCordova && this.allowQueryStringCookies) {
cookie.send();
}
}
};

if (typeof Accounts !== 'undefined' && Accounts !== null) {
DDP.onReconnect((conn) => {
conn.onReconnect = setTokenCookie;
});
Meteor.startup(setTokenCookie);
Accounts.onLogin(setTokenCookie);
}
};

if (typeof Accounts !== 'undefined' && Accounts !== null) {
DDP.onReconnect((conn) => {
conn.onReconnect = setTokenCookie;
});
Meteor.startup(setTokenCookie);
Accounts.onLogin(setTokenCookie);
}

check(this.onbeforeunloadMessage, Match.OneOf(String, Function));
Expand All @@ -130,7 +139,7 @@ export class FilesCollection extends FilesCollectionCore {
const _URL = window.URL || window.webkitURL || window.mozURL || window.msURL || window.oURL || false;
if (window.Worker && window.Blob && _URL && helpers.isFunction(_URL.createObjectURL)) {
this._supportWebWorker = true;
this._webWorkerUrl = _URL.createObjectURL(new window.Blob(['!function(a){"use strict";a.onmessage=function(b){var c=b.data.f.slice(b.data.cs*(b.data.cc-1),b.data.cs*b.data.cc);if(b.data.ib===!0)postMessage({bin:c,chunkId:b.data.cc});else{var d;a.FileReader?(d=new FileReader,d.onloadend=function(a){postMessage({bin:(d.result||a.srcElement||a.target).split(",")[1],chunkId:b.data.cc,s:b.data.s})},d.onerror=function(a){throw(a.target||a.srcElement).error},d.readAsDataURL(c)):a.FileReaderSync?(d=new FileReaderSync,postMessage({bin:d.readAsDataURL(c).split(",")[1],chunkId:b.data.cc})):postMessage({bin:null,chunkId:b.data.cc,error:"File API is not supported in WebWorker!"})}}}(this);'], {type: 'application/javascript'}));
this._webWorkerUrl = _URL.createObjectURL(new window.Blob(['!function(a){"use strict";a.onmessage=function(b){var c=b.data.f.slice(b.data.cs*(b.data.cc-1),b.data.cs*b.data.cc);if(b.data.ib===!0)postMessage({bin:c,chunkId:b.data.cc});else{var d;a.FileReader?(d=new FileReader,d.onloadend=function(a){postMessage({bin:(d.result||a.srcElement||a.target).split(",")[1],chunkId:b.data.cc,s:b.data.s})},d.onerror=function(a){throw(a.target||a.srcElement).error},d.readAsDataURL(c)):a.FileReaderSync?(d=new FileReaderSync,postMessage({bin:d.readAsDataURL(c).split(",")[1],chunkId:b.data.cc})):postMessage({bin:null,chunkId:b.data.cc,error:"File API is not supported in WebWorker!"})}}}(this);'], { type: 'application/javascript' }));
} else if (window.Worker) {
this._supportWebWorker = true;
this._webWorkerUrl = Meteor.absoluteUrl('packages/ostrio_files/worker.min.js');
Expand Down
46 changes: 46 additions & 0 deletions docs/constructor.md
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,52 @@
<strong>Highly recommended to use with Cordova</strong>
</td>
</tr>
<tr>
<td align="right">
<code>config.getUser</code> {<em>Function</em>}
</td>
<td>
Server
</td>
<td>
Replace default way of recognizing user.
<strong>Arguments</strong>:
<ul>
<li>
<code>http</code> {<em>Object</em>} - Middleware request instance
</li>
<li>
<code>http.request</code> {<em>Object</em>} - example: <code>http.request.headers</code>
</li>
<li>
<code>http.response</code> {<em>Object</em>} - example: <code>http.response.end()</code>
</li>
</ul>
</td>
<td>
Default function recognizing user based on x_mtok cookie.
</td>
<td>
Usefull when you want to auth user based on custom cookie (or other way).
Must return null or {userId: null || String, user: function=> null || user }
</td>
</tr>
<tr>
<td align="right">
<code>config.disableSetTokenCookie</code> {<em>Boolean</em>}
</td>
<td>
Client
</td>
<td>
Disable automatic cookie setting
</td>
<td>
</td>
<td>
Useful when you use multiple file collections or when you want to implement your own authorization.
</td>
</tr>
<tr>
<td align="right">
<code>config._preCollection</code> {<em>Mongo.Collection</em>}
Expand Down
2 changes: 1 addition & 1 deletion package.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package.describe({
name: 'ostrio:files',
version: '2.0.0',
version: '2.0.1',
summary: 'Upload files to Meteor application, with 3rd party storage support: AWS:S3, GridFS and other',
git: 'https://github.com/VeliovGroup/Meteor-Files',
documentation: 'README.md'
Expand Down
31 changes: 21 additions & 10 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const NOOP = () => { };
* @param config.onBeforeUpload {Function}- [Both] Function which executes on server after receiving each chunk and on client right before beginning upload. Function context is `File` - so you are able to check for extension, mime-type, size and etc.:
* - return `true` to continue
* - return `false` or `String` to abort upload
* @param config.getUser {Function} - [Server] Replace default way of recognizing user, usefull when you want to auth user based on custom cookie (or other way). arguments {http: {request: {...}, response: {...}}}, need to return {userId: String, user: Function}
* @param config.onInitiateUpload {Function} - [Server] Function which executes on server right before upload is begin and right after `onBeforeUpload` hook. This hook is fully asynchronous.
* @param config.onBeforeRemove {Function} - [Server] Executes before removing file on server, so you can check permissions. Return `true` to allow action and `false` to deny.
* @param config.allowClientCode {Boolean} - [Both] Allow to run `remove` from client
Expand All @@ -78,6 +79,7 @@ export class FilesCollection extends FilesCollectionCore {
schema: this.schema,
public: this.public,
strict: this.strict,
getUser: this.getUser,
chunkSize: this.chunkSize,
protected: this.protected,
collection: this.collection,
Expand Down Expand Up @@ -159,6 +161,10 @@ export class FilesCollection extends FilesCollectionCore {
this.onBeforeUpload = false;
}

if (!helpers.isFunction(this.getUser)) {
this.getUser = false;
}

if (!helpers.isBoolean(this.allowClientCode)) {
this.allowClientCode = true;
}
Expand Down Expand Up @@ -390,6 +396,7 @@ export class FilesCollection extends FilesCollectionCore {
check(this.debug, Boolean);
check(this.schema, Object);
check(this.public, Boolean);
check(this.getUser, Match.OneOf(false, Function));
check(this.protected, Match.OneOf(Boolean, Function));
check(this.chunkSize, Number);
check(this.downloadRoute, String);
Expand Down Expand Up @@ -508,15 +515,7 @@ export class FilesCollection extends FilesCollectionCore {
try {
let opts;
let result;
let user;

if (httpReq.headers['x-mtok'] && this._getUserId(httpReq.headers['x-mtok'])) {
user = {
userId: this._getUserId(httpReq.headers['x-mtok'])
};
} else {
user = this._getUser({request: httpReq, response: httpResp});
}
let user = this._getUser({request: httpReq, response: httpResp});

if (httpReq.headers['x-start'] !== '1') {
// CHUNK UPLOAD SCENARIO:
Expand Down Expand Up @@ -1084,7 +1083,19 @@ export class FilesCollection extends FilesCollectionCore {
* @summary Returns object with `userId` and `user()` method which return user's object
* @returns {Object}
*/
_getUser(http) {
_getUser() {
return this.getUser ?
this.getUser(...arguments) : this._getUserDefault(...arguments);
}

/*
* @locus Anywhere
* @memberOf FilesCollection
* @name _getUserDefault
* @summary Default way of recognising user based on 'x_mtok' cookie, can be replaced by 'config.getUser' if defnied. Returns object with `userId` and `user()` method which return user's object
* @returns {Object}
*/
_getUserDefault(http) {
const result = {
user() { return null; },
userId: null
Expand Down
Loading

0 comments on commit 7db9cfb

Please sign in to comment.