@flashbacktech/flashbackclient 0.0.72 → 0.0.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gcs/index.d.ts +2 -0
- package/dist/gcs/index.js +5 -0
- package/dist/gcs/oauth2.d.ts +29 -0
- package/dist/gcs/oauth2.js +98 -0
- package/dist/gcs/storage.d.ts +22 -0
- package/dist/gcs/storage.js +103 -0
- package/package.json +13 -3
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MockupAuthClient = void 0;
|
|
4
|
+
const oauth2_1 = require("./oauth2");
|
|
5
|
+
Object.defineProperty(exports, "MockupAuthClient", { enumerable: true, get: function () { return oauth2_1.MockupAuthClient; } });
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { OAuth2Client } from 'google-auth-library';
|
|
2
|
+
import { ServiceCredentials } from './storage';
|
|
3
|
+
import { GaxiosResponse } from 'gaxios';
|
|
4
|
+
export declare class MockupAuthClient extends OAuth2Client {
|
|
5
|
+
getRequestHeaders(): Promise<{
|
|
6
|
+
Authorization: string;
|
|
7
|
+
}>;
|
|
8
|
+
}
|
|
9
|
+
export declare class FlashbackAuthClient extends OAuth2Client {
|
|
10
|
+
private authUrl;
|
|
11
|
+
private creds;
|
|
12
|
+
private _credentials;
|
|
13
|
+
private scopes;
|
|
14
|
+
constructor(authUrl: string, scopes: string[], credentials: ServiceCredentials);
|
|
15
|
+
getCredentials(): Promise<{
|
|
16
|
+
client_email: string;
|
|
17
|
+
private_key: string;
|
|
18
|
+
}>;
|
|
19
|
+
getAccessToken(): Promise<{
|
|
20
|
+
token: string | null;
|
|
21
|
+
res: null;
|
|
22
|
+
}>;
|
|
23
|
+
getRequestHeaders(): Promise<Record<string, string>>;
|
|
24
|
+
private ensureValidToken;
|
|
25
|
+
private fetchToken;
|
|
26
|
+
request<T = any>(opts: any): Promise<GaxiosResponse<T>>;
|
|
27
|
+
getRequestMetadata(url?: string): Promise<Record<string, string>>;
|
|
28
|
+
authorizeRequest(reqOpts: any): Promise<any>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FlashbackAuthClient = exports.MockupAuthClient = void 0;
|
|
7
|
+
const google_auth_library_1 = require("google-auth-library");
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
class MockupAuthClient extends google_auth_library_1.OAuth2Client {
|
|
10
|
+
async getRequestHeaders() {
|
|
11
|
+
return {
|
|
12
|
+
Authorization: 'Bearer test-token',
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.MockupAuthClient = MockupAuthClient;
|
|
17
|
+
class FlashbackAuthClient extends google_auth_library_1.OAuth2Client {
|
|
18
|
+
constructor(authUrl, scopes, credentials) {
|
|
19
|
+
super();
|
|
20
|
+
this.authUrl = authUrl;
|
|
21
|
+
this._credentials = null;
|
|
22
|
+
this.creds = credentials;
|
|
23
|
+
this.scopes = scopes;
|
|
24
|
+
console.log('FlashbackAuthClient created with URL:', authUrl);
|
|
25
|
+
}
|
|
26
|
+
async getCredentials() {
|
|
27
|
+
return {
|
|
28
|
+
client_email: this.creds.client_email,
|
|
29
|
+
private_key: this.creds.private_key,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async getAccessToken() {
|
|
33
|
+
await this.ensureValidToken();
|
|
34
|
+
return {
|
|
35
|
+
token: this._credentials?.access_token || null,
|
|
36
|
+
res: null
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async getRequestHeaders() {
|
|
40
|
+
await this.ensureValidToken();
|
|
41
|
+
return {
|
|
42
|
+
Authorization: `Bearer ${this._credentials?.access_token}`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async ensureValidToken() {
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
if (!this._credentials?.access_token || !this._credentials?.expiry_date || now >= this._credentials.expiry_date) {
|
|
48
|
+
await this.fetchToken();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async fetchToken() {
|
|
52
|
+
const response = await axios_1.default.post(this.authUrl, {
|
|
53
|
+
client_email: this.creds.client_email,
|
|
54
|
+
private_key: this.creds.private_key,
|
|
55
|
+
scopes: this.scopes,
|
|
56
|
+
});
|
|
57
|
+
const { access_token, expires_in } = response.data;
|
|
58
|
+
this._credentials = {
|
|
59
|
+
access_token,
|
|
60
|
+
expiry_date: Date.now() + (expires_in * 1000) - 10000,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async request(opts) {
|
|
64
|
+
await this.ensureValidToken();
|
|
65
|
+
const headers = {
|
|
66
|
+
...(opts.headers || {}),
|
|
67
|
+
Authorization: `Bearer ${this._credentials?.access_token}`,
|
|
68
|
+
};
|
|
69
|
+
const response = await axios_1.default.request({
|
|
70
|
+
...opts,
|
|
71
|
+
headers,
|
|
72
|
+
});
|
|
73
|
+
return {
|
|
74
|
+
config: opts,
|
|
75
|
+
data: response.data,
|
|
76
|
+
headers: response.headers,
|
|
77
|
+
status: response.status,
|
|
78
|
+
statusText: response.statusText,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async getRequestMetadata(url) {
|
|
82
|
+
await this.ensureValidToken();
|
|
83
|
+
return {
|
|
84
|
+
Authorization: `Bearer ${this._credentials?.access_token}`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
async authorizeRequest(reqOpts) {
|
|
88
|
+
await this.ensureValidToken();
|
|
89
|
+
return {
|
|
90
|
+
...reqOpts,
|
|
91
|
+
headers: {
|
|
92
|
+
...(reqOpts.headers || {}),
|
|
93
|
+
Authorization: `Bearer ${this._credentials?.access_token}`,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.FlashbackAuthClient = FlashbackAuthClient;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Storage, StorageOptions, File } from '@google-cloud/storage';
|
|
2
|
+
export interface ServiceCredentials {
|
|
3
|
+
client_email: string;
|
|
4
|
+
private_key: string;
|
|
5
|
+
}
|
|
6
|
+
export interface FlashbackStorageOptions extends Omit<StorageOptions, 'authClient'> {
|
|
7
|
+
apiEndpoint?: string;
|
|
8
|
+
tokenScopes?: string[];
|
|
9
|
+
credentials: ServiceCredentials;
|
|
10
|
+
}
|
|
11
|
+
export interface SignedUrlOptions {
|
|
12
|
+
version: 'v4';
|
|
13
|
+
action: 'write' | 'read';
|
|
14
|
+
expires: number;
|
|
15
|
+
contentType: string;
|
|
16
|
+
file: File;
|
|
17
|
+
}
|
|
18
|
+
export declare class FlashbackGCSStorage extends Storage {
|
|
19
|
+
protected credentials: ServiceCredentials;
|
|
20
|
+
constructor(opts: FlashbackStorageOptions);
|
|
21
|
+
getSignedUrl(cfg: SignedUrlOptions): Promise<[string]>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FlashbackGCSStorage = void 0;
|
|
7
|
+
const storage_1 = require("@google-cloud/storage");
|
|
8
|
+
const oauth2_1 = require("./oauth2");
|
|
9
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
10
|
+
class FlashbackGCSStorage extends storage_1.Storage {
|
|
11
|
+
constructor(opts) {
|
|
12
|
+
const { credentials, apiEndpoint = 'https://gcs.us-east-1.flashback.tech', tokenScopes = ['READ', 'WRITE'], ...rest } = opts;
|
|
13
|
+
const authClient = new oauth2_1.FlashbackAuthClient(apiEndpoint + '/token', tokenScopes, credentials);
|
|
14
|
+
// Intercept Gaxios instance creation
|
|
15
|
+
const originalRequest = require('gaxios').instance.request;
|
|
16
|
+
require('gaxios').instance.request = async function (opts) {
|
|
17
|
+
// Add auth headers to all requests
|
|
18
|
+
const headers = await authClient.getRequestHeaders();
|
|
19
|
+
opts.headers = {
|
|
20
|
+
...(opts.headers || {}),
|
|
21
|
+
...headers,
|
|
22
|
+
};
|
|
23
|
+
return originalRequest.call(this, opts);
|
|
24
|
+
};
|
|
25
|
+
super({
|
|
26
|
+
...rest,
|
|
27
|
+
apiEndpoint,
|
|
28
|
+
authClient,
|
|
29
|
+
useAuthWithCustomEndpoint: true,
|
|
30
|
+
retryOptions: {
|
|
31
|
+
autoRetry: true,
|
|
32
|
+
maxRetries: 3,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
this.credentials = credentials;
|
|
36
|
+
}
|
|
37
|
+
// Override the getSignedUrl method
|
|
38
|
+
async getSignedUrl(cfg) {
|
|
39
|
+
const { version, action, expires, contentType } = cfg;
|
|
40
|
+
const accessibleAt = new Date();
|
|
41
|
+
const millisecondsToSeconds = 1.0 / 1000.0;
|
|
42
|
+
const expiresPeriodInSeconds = Math.floor((expires - accessibleAt.valueOf()) * millisecondsToSeconds);
|
|
43
|
+
console.log('Signing Parameters:', {
|
|
44
|
+
action,
|
|
45
|
+
expires,
|
|
46
|
+
expiresPeriodInSeconds,
|
|
47
|
+
accessibleAt: accessibleAt.toISOString(),
|
|
48
|
+
contentType
|
|
49
|
+
});
|
|
50
|
+
if (expiresPeriodInSeconds > 604800) { // 7 days in seconds
|
|
51
|
+
throw new Error('Max allowed expiration is seven days (604800 seconds).');
|
|
52
|
+
}
|
|
53
|
+
const extensionHeaders = {};
|
|
54
|
+
extensionHeaders.host = new URL(this.apiEndpoint).hostname;
|
|
55
|
+
if (contentType) {
|
|
56
|
+
extensionHeaders['content-type'] = contentType;
|
|
57
|
+
}
|
|
58
|
+
const signedHeaders = Object.keys(extensionHeaders)
|
|
59
|
+
.map(header => header.toLowerCase())
|
|
60
|
+
.sort()
|
|
61
|
+
.join(';');
|
|
62
|
+
const canonicalHeaders = Object.entries(extensionHeaders)
|
|
63
|
+
.map(([key, value]) => `${key.toLowerCase()}:${value}`)
|
|
64
|
+
.join('\n') + '\n';
|
|
65
|
+
const datestamp = accessibleAt.toISOString().split('T')[0];
|
|
66
|
+
const credentialScope = `${datestamp}/auto/storage/goog4_request`;
|
|
67
|
+
const credential = `${this.credentials.client_email}/${credentialScope}`;
|
|
68
|
+
const dateISO = accessibleAt.toISOString().replace(/[:-]|\.\d{3}/g, '');
|
|
69
|
+
const queryParams = {
|
|
70
|
+
'X-Goog-Algorithm': 'GOOG4-RSA-SHA256',
|
|
71
|
+
'X-Goog-Credential': credential,
|
|
72
|
+
'X-Goog-Date': dateISO,
|
|
73
|
+
'X-Goog-Expires': expiresPeriodInSeconds.toString(),
|
|
74
|
+
'X-Goog-SignedHeaders': signedHeaders,
|
|
75
|
+
};
|
|
76
|
+
const canonicalQueryString = Object.entries(queryParams)
|
|
77
|
+
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
|
78
|
+
.join('&');
|
|
79
|
+
const canonicalRequest = [
|
|
80
|
+
action === 'read' ? 'GET' : 'PUT',
|
|
81
|
+
`/${cfg.file.bucket.name}/${cfg.file.name}`,
|
|
82
|
+
canonicalQueryString,
|
|
83
|
+
canonicalHeaders,
|
|
84
|
+
signedHeaders,
|
|
85
|
+
'UNSIGNED-PAYLOAD',
|
|
86
|
+
].join('\n');
|
|
87
|
+
console.log('Canonical Request:', canonicalRequest);
|
|
88
|
+
console.log('Canonical Request Hash:', crypto_1.default.createHash('sha256').update(canonicalRequest).digest('hex'));
|
|
89
|
+
const stringToSign = [
|
|
90
|
+
'GOOG4-RSA-SHA256',
|
|
91
|
+
dateISO,
|
|
92
|
+
credentialScope,
|
|
93
|
+
crypto_1.default.createHash('sha256').update(canonicalRequest).digest('hex'),
|
|
94
|
+
].join('\n');
|
|
95
|
+
console.log('String to Sign:', stringToSign);
|
|
96
|
+
const sign = crypto_1.default.createSign('RSA-SHA256');
|
|
97
|
+
sign.update(stringToSign);
|
|
98
|
+
const signature = sign.sign(this.credentials.private_key, 'hex');
|
|
99
|
+
console.log('Generated Signature:', signature);
|
|
100
|
+
return [`${this.apiEndpoint}/${cfg.file.bucket.name}/${cfg.file.name}?${canonicalQueryString}&X-Goog-Signature=${signature}`];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.FlashbackGCSStorage = FlashbackGCSStorage;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flashbacktech/flashbackclient",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.74",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -25,7 +25,9 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@aws-sdk/client-sts": "^3.777.0",
|
|
27
27
|
"@stellar/stellar-sdk": "^13.0.0",
|
|
28
|
-
"formdata-node": "^6.0.3"
|
|
28
|
+
"formdata-node": "^6.0.3",
|
|
29
|
+
"@google-cloud/storage": "^7.15.0",
|
|
30
|
+
"google-auth-library": "^9.15.1"
|
|
29
31
|
},
|
|
30
32
|
"bin": {
|
|
31
33
|
"": "./dist/.min.js"
|
|
@@ -40,6 +42,11 @@
|
|
|
40
42
|
"types": "./dist/api/index.d.ts",
|
|
41
43
|
"require": "./dist/api/index.js",
|
|
42
44
|
"default": "./dist/api/index.js"
|
|
45
|
+
},
|
|
46
|
+
"./gcs": {
|
|
47
|
+
"types": "./dist/gcs/index.d.ts",
|
|
48
|
+
"require": "./dist/gcs/index.js",
|
|
49
|
+
"default": "./dist/gcs/index.js"
|
|
43
50
|
}
|
|
44
51
|
},
|
|
45
52
|
"files": [
|
|
@@ -47,8 +54,8 @@
|
|
|
47
54
|
],
|
|
48
55
|
"devDependencies": {
|
|
49
56
|
"@aws-sdk/client-s3": "^3.777.0",
|
|
57
|
+
"@aws-sdk/s3-request-presigner": "^3.782.0",
|
|
50
58
|
"@eslint/js": "^8.56.0",
|
|
51
|
-
"@google-cloud/storage": "^7.15.0",
|
|
52
59
|
"@types/jest": "^29.5.14",
|
|
53
60
|
"@types/node": "^22.10.1",
|
|
54
61
|
"@types/node-fetch": "^2.6.12",
|
|
@@ -71,6 +78,9 @@
|
|
|
71
78
|
],
|
|
72
79
|
"api": [
|
|
73
80
|
"./dist/api/index.d.ts"
|
|
81
|
+
],
|
|
82
|
+
"gcs": [
|
|
83
|
+
"./dist/gcs/index.d.ts"
|
|
74
84
|
]
|
|
75
85
|
}
|
|
76
86
|
}
|