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

[WIP] Type annotation work #655

Closed
wants to merge 12 commits into from
15 changes: 8 additions & 7 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var notify = require('gulp-notify');

var fs = require("fs");
var browserify = require("browserify");
var ts = require('gulp-typescript')
var mocha = require('gulp-mocha')
var eslint = require('gulp-eslint')

Expand All @@ -36,11 +37,11 @@ gulp.task('browserify', ['compile'], function() {
gulp.task('default', ['test', 'browserify'], function() {})

gulp.task('compile', function(cb) {
compile('src/main/**/*.js', 'minio.js', 'dist/main', cb)
compile('src/main/**/*.ts', 'dist/main', cb)
})

gulp.task('test:compile', ['compile'], function(cb) {
compile('src/test/**/*.js', 'minio-test.js', 'dist/test', cb)
compile('src/test/**/*.js', 'dist/test', cb)
})

gulp.task('test', ['compile', 'test:compile'], function() {
Expand All @@ -61,7 +62,7 @@ gulp.task('lint', function() {
})

gulp.task('functional-test', ['compile'], function() {
compile('src/test/functional/*.js', 'functional', 'dist/test/functional/', function() {
compile('src/test/functional/*.js', 'dist/test/functional/', function() {
gulp.src('dist/test/functional/*.js', {
read: false
})
Expand All @@ -72,11 +73,11 @@ gulp.task('functional-test', ['compile'], function() {
})
})

function compile(src, name, dest, cb) {
function compile(src, dest, cb) {
var tsproject = ts.createProject('tsconfig.json')
gulp.src(src)
.pipe(sourcemaps.init())
.pipe(babel())
.pipe(sourcemaps.write('.'))
.pipe(tsproject())
.js
.pipe(gulp.dest(dest))
.on('end', function() {
cb()
Expand Down
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
"xml2js": "^0.4.15"
},
"devDependencies": {
"@types/es6-error": "^4.0.0",
"@types/lodash": "^4.14.71",
"@types/node": "^8.0.17",
"browserify": "^12.0.1",
"chai": "^3.4.0",
"eslint": "^4.1.1",
Expand All @@ -54,10 +57,12 @@
"gulp-mocha": "^2.1.0",
"gulp-notify": "^2.2.0",
"gulp-sourcemaps": "^1.5.2",
"gulp-typescript": "^3.2.1",
"mocha": "^2.3.2",
"nock": "^2.12.0",
"rewire": "^2.3.3",
"superagent": "^1.6.1"
"superagent": "^1.6.1",
"typescript": "^2.5.0-dev.20170727"
},
"keywords": [
"api",
Expand Down
55 changes: 33 additions & 22 deletions src/main/bucket-policy.js → src/main/bucket-policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,27 @@
* limitations under the License.
*/

import _ from 'lodash'
import * as _ from 'lodash'
import * as errors from './errors'
import { isValidBucketName } from './helpers'

export const Policy = {
NONE: 'none',
READONLY: 'readonly',
WRITEONLY: 'writeonly',
READWRITE: 'readwrite'
type PrincipalKey = 'AWS'
type PrincipalValue = '*'
type Condition = { StringEquals: { 's3:prefix': string } }
interface Statement {
Sid: string,
Effect: 'Allow' | 'Deny',
Principal: { [k in PrincipalKey]: PrincipalValue[] },
Action: string[],
Resource: string[],
Condition?: Condition
}

export enum Policy {
NONE = 'none',
READONLY = 'readonly',
WRITEONLY = 'writeonly',
READWRITE = 'readwrite'
}

const resourcePrefix = 'arn:aws:s3:::'
Expand All @@ -39,7 +51,7 @@ const writeActions = {
}

// Returns the string version of the bucket policy.
export function parseBucketPolicy(policy, bucketName, objectPrefix) {
export function parseBucketPolicy(policy: { Statement: Statement[] }, bucketName: string, objectPrefix: string) {
let statements = policy.Statement

// If there are no statements, it's none.
Expand All @@ -49,8 +61,8 @@ export function parseBucketPolicy(policy, bucketName, objectPrefix) {
let objectResource = `${resourcePrefix}${bucketName}/${objectPrefix}`

let actions = {
bucket: [],
object: []
bucket: [] as string[],
object: [] as string[]
}

// Loop through the statements and aggregate actions which are allowed.
Expand Down Expand Up @@ -95,7 +107,7 @@ export function parseBucketPolicy(policy, bucketName, objectPrefix) {
}

// Generate a statement payload to submit to S3 based on the given policy.
export function generateBucketPolicy(policy, bucketName, objectPrefix) {
export function generateBucketPolicy(policy: Policy, bucketName: string, objectPrefix: string) {
if (!isValidBucketName(bucketName)) {
throw new errors.InvalidBucketNameError(`Invalid bucket name: ${bucketName}`)
}
Expand All @@ -106,8 +118,8 @@ export function generateBucketPolicy(policy, bucketName, objectPrefix) {

// Merge the actions together based on the given policy.
let actions = {
bucket: [],
object: []
bucket: [] as string[],
object: [] as string[]
}

if (policy == Policy.READONLY || policy == Policy.READWRITE) {
Expand All @@ -130,7 +142,7 @@ export function generateBucketPolicy(policy, bucketName, objectPrefix) {
// one for basic bucket permissions, one for basic object permissions,
// and finally a special statement for ListBucket, which should be
// handled separately.
let statements = []
let statements: Statement[] = []

if (actions.bucket.length > 0) {
statements.push(createStatement(actions.bucket, `${resourcePrefix}${bucketName}`))
Expand Down Expand Up @@ -159,7 +171,7 @@ export function generateBucketPolicy(policy, bucketName, objectPrefix) {
}
}

export function isValidBucketPolicy(policy) {
export function isValidBucketPolicy(policy: any): policy is Policy {
return policy == Policy.NONE ||
policy == Policy.READONLY ||
policy == Policy.WRITEONLY ||
Expand All @@ -169,12 +181,12 @@ export function isValidBucketPolicy(policy) {
// Checks to see if the parent array has all the values in the child array.
// Take the intersection for both. If the lengths are the same, the contents
// of the child are inside the parent.
function isSubArrayOf(parent, child) {
function isSubArrayOf<T>(parent: T[], child: T[]) {
return (_.intersection(parent, child)).length == child.length
}

// Checks if the statement pertains to the given resource. Returns a boolean.
function pertainsTo(statement, resource) {
function pertainsTo(statement: Statement, resource: string) {
let resources = statement.Resource

for (let i = 0; i < resources.length; i++) {
Expand All @@ -185,19 +197,18 @@ function pertainsTo(statement, resource) {
}

// Create an s3 Allow Statement.
function createStatement(action, resource) {
return {
export const createStatement: (acton: string[], resource: string) => Statement =
(action, resource) => ({
Sid: '',
Effect: 'Allow',
Principal: { 'AWS': ['*'] },
Action: action,
Resource: [ resource ]
}
}
Resource: [resource]
})

// AWS will sometimes drop arrays of length 1 for their values, so normalize
// these back to arrays with length 1.
function normalizeStatement(statement) {
function normalizeStatement(statement: Statement) {
if (typeof statement.Principal.AWS === 'string')
statement.Principal.AWS = [ statement.Principal.AWS ]

Expand Down
32 changes: 16 additions & 16 deletions src/main/errors.js → src/main/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,35 @@
* limitations under the License.
*/

import ExtendableError from 'es6-error'
import * as ExtendableError from 'es6-error'

// AnonymousRequestError is generated for anonymous keys on specific
// APIs. NOTE: PresignedURL generation always requires access keys.
export class AnonymousRequestError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}

// InvalidArgumentError is generated for all invalid arguments.
export class InvalidArgumentError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}

// InvalidPortError is generated when a non integer value is provided
// for ports.
export class InvalidPortError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}

// InvalidEndpointError is generated when an invalid end point value is
// provided which does not follow domain standards.
export class InvalidEndpointError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}
Expand All @@ -51,7 +51,7 @@ export class InvalidEndpointError extends ExtendableError {
// provided which does not follow AWS S3 specifications.
// http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html
export class InvalidBucketNameError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}
Expand All @@ -60,76 +60,76 @@ export class InvalidBucketNameError extends ExtendableError {
// provided which does not follow AWS S3 specifications.
// http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html
export class InvalidObjectNameError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}

// AccessKeyRequiredError generated by signature methods when access
// key is not found.
export class AccessKeyRequiredError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}

// SecretKeyRequiredError generated by signature methods when secret
// key is not found.
export class SecretKeyRequiredError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}

// ExpiresParamError generated when expires parameter value is not
// well within stipulated limits.
export class ExpiresParamError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}

// InvalidDateError generated when invalid date is found.
export class InvalidDateError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}

// InvalidPrefixError generated when object prefix provided is invalid
// or does not conform to AWS S3 object key restrictions.
export class InvalidPrefixError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}

// InvalidBucketPolicyError generated when the given bucket policy is invalid.
export class InvalidBucketPolicyError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}

// IncorrectSizeError generated when total data read mismatches with
// the input size.
export class IncorrectSizeError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}

// InvalidXMLError generated when an unknown XML is found.
export class InvalidXMLError extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}

// S3Error is generated for errors returned from S3 server.
// see getErrorTransformer for details
export class S3Error extends ExtendableError {
constructor(message) {
constructor(message: string) {
super(message)
}
}
Loading