Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to latest Google Cloud Storage API (4.7.0) and security fixes #21

Open
wants to merge 62 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
2ec735e
Update to Google Cloud Storage API v4.7.0 and dependencies for securi…
alexandre-steinberg Apr 15, 2020
0db4385
--amend
alexandre-steinberg Apr 15, 2020
5242055
minor fixes
alexandre-steinberg Apr 18, 2020
4059eba
minor fixes
alexandre-steinberg Apr 18, 2020
20647ff
refactor: tests now use jest instead of istanbul
alexandre-steinberg Apr 22, 2020
db06eb6
feat: new constructor options and detailed information in file object
alexandre-steinberg Apr 27, 2020
1a7ae34
destination name fix and updated dependencies
alexandre-steinberg May 7, 2020
e093a7e
build: updates @google-cloud/storage to 5.0.1
alexandre-steinberg May 25, 2020
70e1726
fix: array() method issue - req.files present incorrect filename prop…
alexandre-steinberg Jun 23, 2020
556918c
2.3.0
alexandre-steinberg Jun 23, 2020
85f6e72
:zap: update of package dependencies
alexandre-steinberg Sep 11, 2020
5695e12
Update of package dependencies
alexandre-steinberg Sep 11, 2020
1cf391b
fix: Add mising params in StorageEngine's constructor
duongleh Sep 20, 2020
1bb50f6
Merge pull request #2 from duongle26/master
alexandre-steinberg Nov 17, 2020
757c947
fix: merge Duong Le's fix and dependencies update
alexandre-steinberg Nov 17, 2020
131ce2d
Update of package dependencies
alexandre-steinberg Nov 17, 2020
4f353b6
chore: update changelog
alexandre-steinberg Nov 17, 2020
485b6ed
Update index.d.ts
hudifu316 Feb 26, 2021
2bd44d7
Merge pull request #3 from hudifu316/patch-1
alexandre-steinberg Feb 26, 2021
7454d3a
feat: add `uniformBucketLevelAccess` configuration to allow support f…
wi11e Mar 10, 2021
fad53a8
fix(auth): Allow credentials OR keyFileName
ProbablePrime Mar 28, 2021
ce16118
fix(linkUrl): Swap cloud.google.com to storage.googleapis.com
ProbablePrime Mar 28, 2021
5bdf95d
blobFile scoping per file.
Mar 30, 2021
1407a1d
naming things properly
Mar 30, 2021
362a307
Merge pull request #4 from wi11e/uniform-bucket-access
alexandre-steinberg Mar 30, 2021
f21de6f
Merge pull request #5 from ProbablePrime/fix/credentials
alexandre-steinberg Mar 30, 2021
66130b1
Merge pull request #6 from ProbablePrime/fix/linkUrl
alexandre-steinberg Mar 30, 2021
be74fd5
fix: merge conflicts
alexandre-steinberg Mar 30, 2021
f623c36
:zap: merge fixes and update of package dependencies
alexandre-steinberg Mar 30, 2021
f67cfb3
Merge fixes and update package dependencies
alexandre-steinberg Mar 30, 2021
9535fdf
Fix constructor missing params type checking
Mar 31, 2021
cad9cd5
Add test check when using uniformBucketLevelAccess
Mar 31, 2021
0dc7f85
npm run clean & npm run build
Mar 31, 2021
a473d41
npm i
Mar 31, 2021
58e433c
Merge branch 'JonathanChaochen-uniformBucketLevelAccess-type-patch'
alexandre-steinberg Mar 31, 2021
9a930c7
fix: #8
alexandre-steinberg Mar 31, 2021
c237109
fix: #8
alexandre-steinberg Mar 31, 2021
7475248
:zap: general update of package dependencies
alexandre-steinberg Jun 14, 2021
a581a12
Update of package dependencies
alexandre-steinberg Jun 14, 2021
3c43cfd
fix: invoke callback on file removed
VikalpP Feb 3, 2022
ae62090
Update Packages for Multer
crivera Sep 23, 2022
9791132
Merge pull request #9 from VikalpP/patch-1
alexandre-steinberg Sep 26, 2022
1106917
Merge pull request #10 from crivera/patch-1
alexandre-steinberg Sep 26, 2022
fd0abb7
:zap: update of package dependencies
alexandre-steinberg Sep 26, 2022
caeda63
Update of package dependencies
alexandre-steinberg Sep 26, 2022
fc72bd6
Add prepare script
rodrigoborgesdeoliveira Sep 26, 2022
cc084bc
refactor: gitignore lib folder
VikalpP Sep 30, 2022
561cdf0
Remove unnecessary constraint where creds or keyfile is required for …
zeejers Dec 2, 2022
2ad4a20
Merge pull request #12 from zjsherbondy/gcloud-auth-fallback
alexandre-steinberg Dec 7, 2022
63f4043
Merge pull request #11 from VikalpP/master
alexandre-steinberg Dec 7, 2022
62be36d
:zap: fix #11, fix #12, update of package dependencies, adoption of ES6
alexandre-steinberg Dec 7, 2022
1069f8b
General fixes, adoption of ES6 and Update of package dependencies
alexandre-steinberg Dec 7, 2022
16b898e
:zap: update of package dependencies
alexandre-steinberg Jul 17, 2023
adc9800
Update of package dependencies
alexandre-steinberg Jul 17, 2023
b9791de
feat: allow arbitrary StorageOptions to be passed into Storage client
alanraison Feb 12, 2024
da43d1e
fix: update file linkUrl
alanraison Feb 19, 2024
dc81d67
Merge pull request #13 from NewRedo/master
alexandre-steinberg Feb 19, 2024
4c1c276
Add support for optional filenameEncoding
rugvedkoshiya Feb 20, 2025
8d601c2
Merge pull request #14 from rugvedkoshiya/optional-filename-encoding
alexandre-steinberg Feb 20, 2025
853197d
:zap: update of minor package dependencies
alexandre-steinberg Feb 20, 2025
27185ee
:zap: update of package dependencies
alexandre-steinberg Feb 20, 2025
a18894a
Update of package dependencies
alexandre-steinberg Feb 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,3 @@ typings/

.DS_Store

#istanbul
.nyc_output
coverage
19 changes: 0 additions & 19 deletions .travis.yml

This file was deleted.

139 changes: 139 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Changelog

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## v2.7.0 - 2021-03-30

### Fixes

Update index.d.ts (#3)
uniformBucketLevelAccess enabled support (#4)
Allow credentials OR keyFileName (#5)
Swap cloud.google.com to storage.googleapis.com (#6)
blobFile scoping to field uploaded. (#7)
### Other changes

- Package updates:
@google-cloud/storage 5.5.0 -> 5.8.3
@types/express 4.17.9 -> 4.17.11
@types/jest 26.0.15 -> 26.0.22
@types/multer 1.4.4 -> 1.4.5
@types/node 14.14.7 -> 14.14.37
typescript 4.0.5 -> 4.2.3
uuid 8.3.1 -> 8.3.2

## v2.6.0 - 2020-11-16

### Other changes

- Package updates:
@google-cloud/storage 5.3.0 -> 5.5.0
@types/express 4.17.8 -> 4.17.9
@types/jest 26.0.13 -> 26.0.15
@types/node 14.10.1 -> 14.14.7
jest 26.4.2 -> 26.6.3
typescript 3.9.7 -> 4.0.5
uuid 8.3.0 -> 8.3.1

## v2.5.0 - 2020-11-16

### Fixes

Merge Duong Le's fix: Add mising params in StorageEngine's constructor

## v2.4.0 - 2020-09-11

### Other changes

- Package updates:
@google-cloud/storage 5.1.1 -> 5.3.0
@types/express 4.17.6 -> 4.17.8
@types/jest 25.2.3 -> 26.0.13
@types/multer 1.4.3 -> 1.4.4
@types/node 14.0.13 -> 14.10.1
jest 26.1.0 -> 26.4.2
typescript 3.9.5 -> 3.9.7
uuid 8.1.0 -> 8.3.0

## v2.3.0 - 2020-06-23

### Bug Fixes

- array() method issue: req.files present incorrect filename property

### Other changes

- Package updates:
@google-cloud/storage 5.0.1 -> 5.1.1
@types/jest 25.2.3 -> 26.0.0
@types/node 14.0.5 -> 14.0.13
jest 26.0.1 -> 26.1.0
typescript 3.8.3 -> 3.9.5

## v2.2.0 - 2020-05-25

### ⚠ BREAKING CHANGES

- Dropped support for Node.js <= 8.x

### Other changes

- Package updates:
@google-cloud/storage 4.7.0 -> 5.0.1
@types/jest 25.2.1 -> 25.2.3
@types/node 13.13.5 -> 14.0.5
@types/urlencode 1.1.1 -> 1.1.2
typescript 3.8.3 -> 3.9.3
uuid 8.0.0 -> 8.1.0

## v2.1.1 - 2020-05-07

### Fixes

- destination is not urlencoded anymore

## v2.1.0 - 2020-04-26

### Features

- New options to explicit constructor
- `contentType`: `string`
- `destination`: `string`
- `hideFilename`: `boolean`
- New information available on multer API file object
- `bucket`
- `destination`
- `filename`
- `path`
- `contenType`
- `size`
- `uri`
- `linkUrl`
- `selfLink`

### Fixes

- Now package.json defines engine Node.js >= 10
- Requirement of Google API v4.7.0, not correctly observed on v2.0.0

### Other changes

- Packages added:
- jest
- Packages removed:
- commitizen
- cz-conventional-changelog
- husky
- nyc
- semantic-release

## v2.0.0 - 2020-04-15

### ⚠ BREAKING CHANGES

- Removed support for Node.js < 8.x

### Features

- Update Google Cloud Storage Node.js Client to v4.7.0
- Update dependencies to latest versions (most for security fixes)
11 changes: 11 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Released under MIT License

Copyright (c) 2017 ARozar.

Copyright (c) 2020 Alexandre Steinberg.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
92 changes: 67 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
# multer-google-storage
[![Travis build](https://img.shields.io/travis/ARozar/multer-google-storage.svg)](https://travis-ci.org/ARozar/multer-google-storage/)
# multer-cloud-storage
[![last commit](https://badgen.net/github/last-commit/alexandre-steinberg/multer-cloud-storage)](https://github.com/alexandre-steinberg/multer-cloud-storage)
[![npm version](https://badgen.net/npm/v/multer-cloud-storage)](https://www.npmjs.com/package/multer-cloud-storage)
[![MIT License](https://badgen.net/npm/license/multer-cloud-storage)](https://opensource.org/licenses/MIT)
[![node](https://badgen.net/npm/node/multer-cloud-storage)](https://nodejs.org/en/)
[![packagephobia install size](https://badgen.net/packagephobia/install/multer-cloud-storage)](https://packagephobia.now.sh/result?p=multer-cloud-storage)
[![packagephobia publish size](https://badgen.net/packagephobia/publish/multer-cloud-storage)](https://packagephobia.now.sh/result?p=multer-cloud-storage)

This is a multer storage engine for google's file storage.
multer-cloud-storage is a [multer](https://github.com/expressjs/multer) custom store engine for Google Cloud Storage service. It is a fork from ARozar's [multer-google-storage](https://github.com/ARozar/multer-google-storage) that uses latest version of Google Cloud's API, allows additional information (like destination and contentType) to be set and reduces module footprint.

## Installation
npm install multer-google-storage --save

npm install multer-cloud-storage --save

or

yarn add multer-google-storage
yarn add multer-cloud-storage


## Usage
### ES6

import * as multer from 'multer';
import * as multer from 'multer';
import * as express from 'express';
import MulterGoogleCloudStorage from 'multer-google-storage';
import MulterGoogleCloudStorage from 'multer-cloud-storage';

const app = express();

Expand All @@ -33,7 +39,7 @@ or

var multer = require("multer");
var express = require("express");
var multerGoogleStorage = require("multer-google-storage");
var multerGoogleStorage = require("multer-cloud-storage");
var app = express();
var uploadHandler = multer({
storage: multerGoogleStorage.storageEngine()
Expand All @@ -43,14 +49,15 @@ or
res.json(req.files);
});

NB: This package is written to work with es5 or higher. If you have an editor or IDE that can understand d.ts (typescript) type definitions you will get additional support from your tooling though you do not need to be using typescript to use this package.
NB: This package is written to work with es5 or higher. If you have an editor or IDE that can understand d.ts (typescript) type definitions you will get additional support from your tooling though you do not need to be using typescript to use this package.

## Google Cloud
### Creating a storage bucket
For instructions on how to create a storage bucket see the following [documentation from google](https://cloud.google.com/storage/docs/creating-buckets#storage-create-bucket-console).
For instructions on how to create a storage bucket see the following [documentation from Google](https://cloud.google.com/storage/docs/creating-buckets#storage-create-bucket-console).

### Obtaining credentials
For instructions on how to obtain the JSON keyfile as well a "projectId" (contained in the key file) please refer to the following [documentation from google](https://cloud.google.com/docs/authentication/getting-started)
For instructions on how to obtain the JSON keyfile as well a *projectId* (contained in the key file) please refer to the following [documentation from Google](https://cloud.google.com/docs/authentication/getting-started).

### Credentials
#### Default method
If using the MulterGoogleCloudStorage class without passing in any configuration options then the following environment variables will need to be set:
Expand All @@ -61,21 +68,56 @@ If using the MulterGoogleCloudStorage class without passing in any configuration
#### Explicit method
The constructor of the MulterGoogleCloudStorage class can be passed an optional configuration object.

| Parameter Name | Type | Sample Value |
|---|---|---|
|`autoRetry`|`boolean`| `true`|
|`email`|`string`|`"[email protected]"`|
|`keyFilename`|`string`|`"./key.json"`|
|`maxRetries`|`number`|`2`|
|`projectId`|`string`|`"test-prj-1234"`|
|`filename`| `function`|`(request, file, callback): void`|
|`bucket`|`string`|`"mybucketname"`|
|`contentType`|`function`|`(request, file): string`|
|`acl`|`string`|`"publicread"`|

#### Custom file naming
Parameter Name | Type | Sample Value | Default Value | Notes
--- | --- | --- | --- | ---
`acl`|`string`|`"publicRead"`|`"private"`|Accepted values are defined in [*predefinedAcl*](https://googleapis.dev/nodejs/storage/latest/global.html#CreateWriteStreamOptions) options
`autoRetry`|`boolean`|`true`| `true`|
`bucket`|`string`|`"mybucketname"`| |Takes precedence over GCS_BUCKET
`contentType`|`function`|`(request, file): string`| |
`contentType`|`string`|`"application/pdf"`| |If set, this value will be used in place of *file.mimetype*
`destination`|`string`|`"my_folder/"`|`""`|Despite Google Cloud Storage service stores objects in a flat name space, it is possible to list and filter them in a tree-like structure (more on [How Subdirectories Work article](https://cloud.google.com/storage/docs/gsutil/addlhelp/HowSubdirectoriesWork))
`email`|`string`|`"[email protected]"`| |
`filename`| `function`|`(request, file, callback): void`| |
`filename`| `string`|`"my_file.pdf"`| |If defined, this name will be used in place of *file.originalname* - use with caution, because the object can be easily overwritten (consider to configure [Object Versioning and Concurrency Control](https://cloud.google.com/storage/docs/gsutil/addlhelp/ObjectVersioningandConcurrencyControl))
`hideFilename`|`boolean`|`true`|`false`|If set to *true*, an UUID v4 will be used as object filename and *Content-Type* will be undefined
`keyFilename`|`string`|`"./key.json"`| |Takes precedence over GCS_KEYFILE
`maxRetries`|`number`|`5`|`3`| |
`projectId`|`string`|`"test-prj-1234"`| |Takes precedence over GCLOUD_PROJECT
`uniformBucketLevelAccess`|`boolean`|`true`| |Signifies whether `uniformBucketLevelAccess` is enabled on the target bucket. When `true`, the `predefinedAcl` parameter is removed from requests [as it causes `400 Bad Request` responses](https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request).
#### Custom file naming function
If you need to customize the naming of files then you are able to provide a function that will be called before uploading the file. The third argument of the function must be a standard node callback so pass any error in the first argument (or null on sucess) and the string name of the file on success.

getFilename(req, file, cb) {
cb(null,`${uuid()}_${file.originalname}`);
cb(null,`${file.originalname}`);
}

#### Custom content-type function
If you need to customize the content-type of files then you are able to provide a function that will be called before uploading the file.

getContentType( req, file ) {
return undefined;
}

## Changes in multer API

When used with multer-cloud-storage, multer will present additional file information.

### File information

Each file contains the following information:

Key | Description | Origin
--- | --- | ---
`fieldname` | Field name specified in the form | `multer`
`originalname` | Name of the file on the user's computer | `multer`
`encoding` | Encoding type of the file | `multer`
`mimetype` | Mime type of the file | `multer`
`bucket` | Bucket name | `multer-cloud-storage`
`destination` | The pseudo-folder to which the file has been saved | `multer-cloud-storage`
`filename` | The name of the file on Google Cloud Storage | `multer-cloud-storage`
`path` | The full path to the uploaded file (basically `destination`+ `filename`) | `multer-cloud-storage`
`contentType` | Content-type defined for stored object | `multer-cloud-storage`
`size` | Size of the file in bytes | `multer-cloud-storage`
`uri` | Google Cloud Storage path | `multer-cloud-storage`
`linkUrl` | Download link for allowed users (may require authentication) | `multer-cloud-storage`
`selfLink` | The link to the stored object (used for Cloud Storage APIs requests) | `multer-cloud-storage`
4 changes: 4 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
roots: ['<rootDir>/lib'],
testEnvironment: 'node',
};
24 changes: 15 additions & 9 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
/// <reference types="google-cloud__storage" />
import * as multer from 'multer';
import { ConfigurationObject } from '@google-cloud/storage';
import multer = require('multer');
import { StorageOptions } from '@google-cloud/storage';
import { Request } from 'express';
export default class MulterGoogleCloudStorage implements multer.StorageEngine {
private gcobj;
private gcsBucket;
private gcsStorage;
private options;
getFilename(req: any, file: any, cb: any): void;
getDestination(req: any, file: any, cb: any): void;
getContentType: ContentTypeFunction;
constructor(opts?: ConfigurationObject & {
filename?: any;
getContentType(req: any, file: any): any;
private getBlobFileReference;
constructor(opts?: StorageOptions & {
bucket?: string;
destination?: any;
filename?: any;
hideFilename?: boolean;
contentType?: ContentTypeFunction;
});
_handleFile: (req: any, file: any, cb: any) => void;
_removeFile: (req: any, file: any, cb: any) => void;
}
export declare function storageEngine(opts?: ConfigurationObject & {
filename?: any;
export declare function storageEngine(opts?: StorageOptions & {
bucket?: string;
destination?: any;
filename?: any;
hideFilename?: boolean;
contentType?: ContentTypeFunction;
uniformBucketLevelAccess?: boolean;
}): MulterGoogleCloudStorage;
export declare type ContentTypeFunction = (req: Request, file: Express.Multer.File) => string | undefined;
Loading