Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 2 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ on:

jobs:
release:
name: Node.js
uses: node-modules/github-actions/.github/workflows/node-release.yml@master
name: NPM
uses: node-modules/github-actions/.github/workflows/npm-release.yml@master
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ test/node/.tmp
test/demo.js
yarn.lock
package-lock.json
pnpm-lock.yaml
.nyc_output/
.env

Expand Down
11 changes: 8 additions & 3 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@
"$schema": "./node_modules/oxlint/configuration_schema.json",
"extends": ["./node_modules/@eggjs/oxlint-config/.oxlintrc.json"],
"env": {
"node": true,
"mocha": true
"node": true
},
"rules": {
"no-console": "warn",
"no-empty-function": "allow"
},
"ignorePatterns": ["index.d.ts", "test/fixtures/**", "__snapshots__"]
"ignorePatterns": [
"index.d.ts",
"test/fixtures/**",
"__snapshots__",
"test/*.cjs",
"test/setup.ts"
]
}
24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
"lint": "oxlint",
"pretest": "npm run lint -- --fix",
"test": "vitest run --test-timeout 15000",
"test:cjs": "node test/hello.cjs",
"cov": "npm run test -- --coverage",
"preci": "npm run lint",
"ci": "npm run cov && npm run prepublishOnly && attw --pack",
"ci": "npm run cov && npm run prepublishOnly && attw --pack && npm run test:cjs",
"prepublishOnly": "tshy && tshy-after",
"prepare": "husky"
},
Expand Down Expand Up @@ -43,27 +44,27 @@
"ms": "^2.1.3",
"oss-interface": "^1.3.0",
"stream-wormhole": "^2.0.0",
"urllib": "^4.6.2",
"urllib": "^4.8.1",
"utility": "^2.1.0",
"xml2js": "^0.6.2"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.15.3",
"@arethetypeswrong/cli": "^0.18.2",
"@eggjs/oxlint-config": "^1.0.0",
"@eggjs/tsconfig": "^1.1.0",
"@types/mime": "^3.0.1",
"@types/ms": "^0.7.31",
"@types/node": "^20.3.1",
"@types/ms": "^0.7.34",
"@types/node": "^24.2.1",
"@types/xml2js": "^0.4.12",
"@vitest/coverage-v8": "^3.1.3",
"husky": "^9.1.7",
"oxlint": "^0.16.10",
"oxlint": "^1.11.0",
"prettier": "^3.5.3",
"read-env-value": "^1.0.1",
"tshy": "^1.0.0",
"read-env-value": "^2.0.2",
"tshy": "^3.0.2",
"tshy-after": "^1.0.0",
"typescript": "^5.2.2",
"vitest": "^3.1.3"
"vitest": "^3.2.4"
},
"files": [
"dist",
Expand All @@ -80,17 +81,16 @@
"./package.json": "./package.json",
".": {
"import": {
"source": "./src/index.ts",
"types": "./dist/esm/index.d.ts",
"default": "./dist/esm/index.js"
},
"require": {
"source": "./src/index.ts",
"types": "./dist/commonjs/index.d.ts",
"default": "./dist/commonjs/index.js"
}
}
},
"types": "./dist/commonjs/index.d.ts",
"main": "./dist/commonjs/index.js"
"main": "./dist/commonjs/index.js",
"module": "./dist/esm/index.js"
}
21 changes: 12 additions & 9 deletions src/util/sign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ import { encodeCallback } from './encodeCallback.js';
const debug = debuglog('oss-client:sign');
const OSS_PREFIX = 'x-oss-';

function compareCanonicalizedString(entry1: string, entry2: string) {
if (entry1[0] > entry2[0]) {
return 1;
} else if (entry1[0] < entry2[0]) {
return -1;
}
return 0;
}

/**
* build canonicalized resource
* @see https://help.aliyun.com/zh/oss/developer-reference/include-signatures-in-the-authorization-header#section-rvv-dx2-xdb
Expand All @@ -29,22 +38,16 @@ function buildCanonicalizedResource(
parameters.sort();
canonicalizedResource += separatorString + parameters.join('&');
} else if (parameters) {
const compareFunc = (entry1: string, entry2: string) => {
if (entry1[0] > entry2[0]) {
return 1;
} else if (entry1[0] < entry2[0]) {
return -1;
}
return 0;
};
const processFunc = (key: string) => {
canonicalizedResource += separatorString + key;
if (parameters[key] || parameters[key] === 0) {
canonicalizedResource += `=${parameters[key]}`;
}
separatorString = '&';
};
for (const key of Object.keys(parameters).sort(compareFunc)) {
for (const key of Object.keys(parameters).sort(
compareCanonicalizedString
)) {
processFunc(key);
}
}
Expand Down
47 changes: 27 additions & 20 deletions test/OSSObject.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -983,26 +983,33 @@ describe('test/OSSObject.test.ts', () => {
assert.equal(getResult.res.headers.etag, httpStream.headers.etag);
});

it('should add very big file: 4mb with streaming way', async () => {
name = `${prefix}oss-client/oss/bigfile-4mb.bin`;
const bigFile = path.join(tmpdir, 'bigfile-4mb.bin');
await writeFile(bigFile, Buffer.alloc(4 * 1024 * 1024).fill('a\n'));
const object = await ossObject.putStream(name, createReadStream(bigFile));
assert.equal(typeof object.res.headers['x-oss-request-id'], 'string');
assert.equal(typeof object.res.rt, 'number');
assert.equal(object.res.size, 0);
assert.equal(object.name, name);

// check content
const r = await ossObject.get(name);
assert.equal(r.res.status, 200);
assert.equal(r.res.headers['content-type'], 'application/octet-stream');
assert.equal(r.res.size, 4 * 1024 * 1024);
const buf = await readFile(bigFile);
assert.ok(r.content);
assert.equal(r.content.length, buf.length);
assert.deepEqual(r.content, buf);
});
// timeout on Node.js 18
it.skipIf(process.version.startsWith('v18.'))(
'should add very big file: 4mb with streaming way',
async () => {
name = `${prefix}oss-client/oss/bigfile-4mb.bin`;
const bigFile = path.join(tmpdir, 'bigfile-4mb.bin');
await writeFile(bigFile, Buffer.alloc(4 * 1024 * 1024).fill('a\n'));
const object = await ossObject.putStream(
name,
createReadStream(bigFile)
);
assert.equal(typeof object.res.headers['x-oss-request-id'], 'string');
assert.equal(typeof object.res.rt, 'number');
assert.equal(object.res.size, 0);
assert.equal(object.name, name);

// check content
const r = await ossObject.get(name);
assert.equal(r.res.status, 200);
assert.equal(r.res.headers['content-type'], 'application/octet-stream');
assert.equal(r.res.size, 4 * 1024 * 1024);
const buf = await readFile(bigFile);
assert.ok(r.content);
assert.equal(r.content.length, buf.length);
assert.deepEqual(r.content, buf);
}
);

it('should throw error with stream destroy', async () => {
name = `${prefix}oss-client/oss/putStream-source-destroy.js`;
Expand Down
11 changes: 11 additions & 0 deletions test/hello.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { OSSObject } = require('..');

const ossObject = new OSSObject({
region: 'oss-cn-hangzhou',
endpoint: 'https://oss-cn-hangzhou.aliyuncs.com',
accessKeyId: 'LTAI5tG666666666666666',
accessKeySecret: '66666666666666666666666666666666',
bucket: 'foo',
Comment on lines +6 to +8
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Avoid hardcoded secrets and logging sensitive config

Even as placeholders, committing credentials and logging the constructed client can leak secrets if envs are used later. Use env vars with safe fallbacks and avoid logging the full object.

-  accessKeyId: 'LTAI5tG666666666666666',
-  accessKeySecret: '66666666666666666666666666666666',
+  accessKeyId: process.env.OSS_ACCESS_KEY_ID || 'test-ak',
+  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET || 'test-secret',
@@
-console.log(ossObject);
+require('node:assert').ok(ossObject);

Also applies to: 11-11

🤖 Prompt for AI Agents
In test/hello.cjs around lines 6 to 8 and line 11, avoid hardcoding sensitive
credentials like accessKeyId and accessKeySecret directly in the code. Instead,
read these values from environment variables with safe fallback defaults if
needed. Also, remove or modify any logging of the full client object to prevent
accidental exposure of secrets.

});

console.log(ossObject);
7 changes: 7 additions & 0 deletions test/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { File } from 'node:buffer';

// multi undici version in node version less than 20 https://github.com/nodejs/undici/issues/4374
if (typeof global.File === 'undefined') {
// @ts-ignore
global.File = File;
}
7 changes: 7 additions & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { defineConfig } from 'vitest/config';

export default defineConfig({
test: {
setupFiles: ['test/setup.ts'],
},
});