@flashbacktech/flashbackclient 0.0.73 → 0.0.75

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.
@@ -1,5 +1,6 @@
1
1
  import { OAuth2Client } from 'google-auth-library';
2
2
  import { ServiceCredentials } from './storage';
3
+ import { GaxiosResponse } from 'gaxios';
3
4
  export declare class MockupAuthClient extends OAuth2Client {
4
5
  getRequestHeaders(): Promise<{
5
6
  Authorization: string;
@@ -7,13 +8,22 @@ export declare class MockupAuthClient extends OAuth2Client {
7
8
  }
8
9
  export declare class FlashbackAuthClient extends OAuth2Client {
9
10
  private authUrl;
11
+ private creds;
12
+ private _credentials;
10
13
  private scopes;
11
- private token;
12
- private tokenExpiry;
13
- private clientEmail;
14
- private privateKey;
15
14
  constructor(authUrl: string, scopes: string[], credentials: ServiceCredentials);
16
- private fetchToken;
17
- private ensureValidToken;
15
+ getCredentials(): Promise<{
16
+ client_email: string;
17
+ private_key: string;
18
+ }>;
19
+ getAccessToken(): Promise<{
20
+ token: string | null;
21
+ res: null;
22
+ }>;
18
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>;
19
29
  }
@@ -18,31 +18,80 @@ class FlashbackAuthClient extends google_auth_library_1.OAuth2Client {
18
18
  constructor(authUrl, scopes, credentials) {
19
19
  super();
20
20
  this.authUrl = authUrl;
21
+ this._credentials = null;
22
+ this.creds = credentials;
21
23
  this.scopes = scopes;
22
- this.token = null;
23
- this.tokenExpiry = null;
24
- this.clientEmail = credentials.client_email;
25
- this.privateKey = credentials.private_key;
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
+ }
26
50
  }
27
51
  async fetchToken() {
28
52
  const response = await axios_1.default.post(this.authUrl, {
29
- client_email: this.clientEmail,
30
- private_key: this.privateKey,
53
+ client_email: this.creds.client_email,
54
+ private_key: this.creds.private_key,
31
55
  scopes: this.scopes,
32
56
  });
33
57
  const { access_token, expires_in } = response.data;
34
- this.token = access_token;
35
- this.tokenExpiry = Date.now() + (expires_in * 1000) - 10000;
58
+ this._credentials = {
59
+ access_token,
60
+ expiry_date: Date.now() + (expires_in * 1000) - 10000,
61
+ };
36
62
  }
37
- async ensureValidToken() {
38
- if (!this.token || !this.tokenExpiry || Date.now() >= this.tokenExpiry) {
39
- await this.fetchToken();
40
- }
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
+ };
41
80
  }
42
- async getRequestHeaders() {
81
+ async getRequestMetadata(url) {
82
+ await this.ensureValidToken();
83
+ return {
84
+ Authorization: `Bearer ${this._credentials?.access_token}`,
85
+ };
86
+ }
87
+ async authorizeRequest(reqOpts) {
43
88
  await this.ensureValidToken();
44
89
  return {
45
- Authorization: `Bearer ${this.token}`,
90
+ ...reqOpts,
91
+ headers: {
92
+ ...(reqOpts.headers || {}),
93
+ Authorization: `Bearer ${this._credentials?.access_token}`,
94
+ },
46
95
  };
47
96
  }
48
97
  }
@@ -1,4 +1,4 @@
1
- import { Storage, StorageOptions } from '@google-cloud/storage';
1
+ import { Storage, StorageOptions, File } from '@google-cloud/storage';
2
2
  export interface ServiceCredentials {
3
3
  client_email: string;
4
4
  private_key: string;
@@ -8,6 +8,17 @@ export interface FlashbackStorageOptions extends Omit<StorageOptions, 'authClien
8
8
  tokenScopes?: string[];
9
9
  credentials: ServiceCredentials;
10
10
  }
11
+ export interface SignedUrlOptions {
12
+ version: 'v4';
13
+ action: 'write' | 'read' | 'delete';
14
+ expires: number;
15
+ contentType: string;
16
+ file: File;
17
+ }
11
18
  export declare class FlashbackGCSStorage extends Storage {
19
+ protected credentials: ServiceCredentials;
12
20
  constructor(opts: FlashbackStorageOptions);
21
+ cleanup(): void;
22
+ bucket(name: string): import("@google-cloud/storage").Bucket;
23
+ getSignedUrl(cfg: SignedUrlOptions): Promise<[string]>;
13
24
  }
@@ -1,19 +1,122 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.FlashbackGCSStorage = void 0;
4
7
  const storage_1 = require("@google-cloud/storage");
5
8
  const oauth2_1 = require("./oauth2");
9
+ const crypto_1 = __importDefault(require("crypto"));
10
+ const originalRequest = require('gaxios').instance.request;
6
11
  class FlashbackGCSStorage extends storage_1.Storage {
7
12
  constructor(opts) {
8
13
  const { credentials, apiEndpoint = 'https://gcs.us-east-1.flashback.tech', tokenScopes = ['READ', 'WRITE'], ...rest } = opts;
9
- //const authClient = new FlashbackAuthClient(apiEndpoint + '/token', tokenScopes, credentials!);
10
- const authClient = new oauth2_1.MockupAuthClient();
14
+ const authClient = new oauth2_1.FlashbackAuthClient(apiEndpoint + '/token', tokenScopes, credentials);
11
15
  super({
12
16
  ...rest,
13
17
  apiEndpoint,
14
18
  authClient,
15
19
  useAuthWithCustomEndpoint: true,
20
+ retryOptions: {
21
+ autoRetry: true,
22
+ maxRetries: 3,
23
+ },
16
24
  });
25
+ this.credentials = credentials;
26
+ // Intercept Gaxios instance creation
27
+ require('gaxios').instance.request = async function (opts) {
28
+ // Add auth headers to all requests
29
+ const headers = await authClient.getRequestHeaders();
30
+ opts.headers = {
31
+ ...(opts.headers || {}),
32
+ ...headers,
33
+ };
34
+ return originalRequest.call(this, opts);
35
+ };
36
+ }
37
+ cleanup() {
38
+ require('gaxios').instance.request = originalRequest;
39
+ }
40
+ // Override the bucket method to ensure we pass the auth client
41
+ bucket(name) {
42
+ return super.bucket(name);
43
+ }
44
+ // Override the getSignedUrl method
45
+ async getSignedUrl(cfg) {
46
+ const { version, action, expires, contentType } = cfg;
47
+ const accessibleAt = new Date();
48
+ const millisecondsToSeconds = 1.0 / 1000.0;
49
+ const expiresPeriodInSeconds = Math.floor((expires - accessibleAt.valueOf()) * millisecondsToSeconds);
50
+ console.log('Signing Parameters:', {
51
+ action,
52
+ expires,
53
+ expiresPeriodInSeconds,
54
+ accessibleAt: accessibleAt.toISOString(),
55
+ contentType
56
+ });
57
+ if (expiresPeriodInSeconds > 604800) { // 7 days in seconds
58
+ throw new Error('Max allowed expiration is seven days (604800 seconds).');
59
+ }
60
+ const extensionHeaders = {};
61
+ extensionHeaders.host = new URL(this.apiEndpoint).hostname;
62
+ if (contentType) {
63
+ extensionHeaders['content-type'] = contentType;
64
+ }
65
+ const signedHeaders = Object.keys(extensionHeaders)
66
+ .map(header => header.toLowerCase())
67
+ .sort()
68
+ .join(';');
69
+ const canonicalHeaders = Object.entries(extensionHeaders)
70
+ .map(([key, value]) => `${key.toLowerCase()}:${value}`)
71
+ .join('\n') + '\n';
72
+ const datestamp = accessibleAt.toISOString().split('T')[0];
73
+ const credentialScope = `${datestamp}/auto/storage/goog4_request`;
74
+ const credential = `${this.credentials.client_email}/${credentialScope}`;
75
+ const dateISO = accessibleAt.toISOString().replace(/[:-]|\.\d{3}/g, '');
76
+ const queryParams = {
77
+ 'X-Goog-Algorithm': 'GOOG4-RSA-SHA256',
78
+ 'X-Goog-Credential': credential,
79
+ 'X-Goog-Date': dateISO,
80
+ 'X-Goog-Expires': expiresPeriodInSeconds.toString(),
81
+ 'X-Goog-SignedHeaders': signedHeaders,
82
+ };
83
+ const canonicalQueryString = Object.entries(queryParams)
84
+ .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
85
+ .join('&');
86
+ let method;
87
+ switch (action) {
88
+ case 'read':
89
+ method = 'GET';
90
+ break;
91
+ case 'delete':
92
+ method = 'DELETE';
93
+ break;
94
+ default:
95
+ method = 'PUT';
96
+ break;
97
+ }
98
+ const canonicalRequest = [
99
+ method,
100
+ `/${cfg.file.bucket.name}/${cfg.file.name}`,
101
+ canonicalQueryString,
102
+ canonicalHeaders,
103
+ signedHeaders,
104
+ 'UNSIGNED-PAYLOAD',
105
+ ].join('\n');
106
+ console.log('Canonical Request:', canonicalRequest);
107
+ console.log('Canonical Request Hash:', crypto_1.default.createHash('sha256').update(canonicalRequest).digest('hex'));
108
+ const stringToSign = [
109
+ 'GOOG4-RSA-SHA256',
110
+ dateISO,
111
+ credentialScope,
112
+ crypto_1.default.createHash('sha256').update(canonicalRequest).digest('hex'),
113
+ ].join('\n');
114
+ console.log('String to Sign:', stringToSign);
115
+ const sign = crypto_1.default.createSign('RSA-SHA256');
116
+ sign.update(stringToSign);
117
+ const signature = sign.sign(this.credentials.private_key, 'hex');
118
+ console.log('Generated Signature:', signature);
119
+ return [`${this.apiEndpoint}/${cfg.file.bucket.name}/${cfg.file.name}?${canonicalQueryString}&X-Goog-Signature=${signature}`];
17
120
  }
18
121
  }
19
122
  exports.FlashbackGCSStorage = FlashbackGCSStorage;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flashbacktech/flashbackclient",
3
- "version": "0.0.73",
3
+ "version": "0.0.75",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },