@mcp-abap-adt/auth-broker 0.1.5 → 0.1.7
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/CHANGELOG.md +244 -0
- package/README.md +181 -16
- package/bin/generate-env-from-service-key.ts +128 -0
- package/dist/AuthBroker.d.ts +47 -31
- package/dist/AuthBroker.d.ts.map +1 -1
- package/dist/AuthBroker.js +182 -134
- package/dist/__tests__/helpers/configHelpers.d.ts +49 -0
- package/dist/__tests__/helpers/configHelpers.d.ts.map +1 -0
- package/dist/__tests__/helpers/configHelpers.js +169 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -8
- package/dist/providers/ITokenProvider.d.ts +49 -0
- package/dist/providers/ITokenProvider.d.ts.map +1 -0
- package/dist/providers/ITokenProvider.js +10 -0
- package/dist/providers/index.d.ts +8 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +8 -0
- package/dist/stores/index.d.ts +5 -5
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/index.js +4 -8
- package/dist/stores/interfaces.d.ts +88 -22
- package/dist/stores/interfaces.d.ts.map +1 -1
- package/dist/stores/interfaces.js +1 -2
- package/dist/types.d.ts +7 -31
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -0
- package/package.json +13 -6
- package/dist/__tests__/testHelpers.d.ts +0 -44
- package/dist/__tests__/testHelpers.d.ts.map +0 -1
- package/dist/__tests__/testHelpers.js +0 -136
- package/dist/browserAuth.d.ts +0 -17
- package/dist/browserAuth.d.ts.map +0 -1
- package/dist/browserAuth.js +0 -305
- package/dist/cache.d.ts +0 -20
- package/dist/cache.d.ts.map +0 -1
- package/dist/cache.js +0 -46
- package/dist/envLoader.d.ts +0 -12
- package/dist/envLoader.d.ts.map +0 -1
- package/dist/envLoader.js +0 -90
- package/dist/getToken.d.ts +0 -14
- package/dist/getToken.d.ts.map +0 -1
- package/dist/getToken.js +0 -62
- package/dist/logger.d.ts +0 -40
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -186
- package/dist/pathResolver.d.ts +0 -21
- package/dist/pathResolver.d.ts.map +0 -1
- package/dist/pathResolver.js +0 -105
- package/dist/refreshToken.d.ts +0 -14
- package/dist/refreshToken.d.ts.map +0 -1
- package/dist/refreshToken.js +0 -71
- package/dist/serviceKeyLoader.d.ts +0 -12
- package/dist/serviceKeyLoader.d.ts.map +0 -1
- package/dist/serviceKeyLoader.js +0 -72
- package/dist/stores/FileServiceKeyStore.d.ts +0 -38
- package/dist/stores/FileServiceKeyStore.d.ts.map +0 -1
- package/dist/stores/FileServiceKeyStore.js +0 -47
- package/dist/stores/FileSessionStore.d.ts +0 -50
- package/dist/stores/FileSessionStore.d.ts.map +0 -1
- package/dist/stores/FileSessionStore.js +0 -116
- package/dist/stores/SafeSessionStore.d.ts +0 -35
- package/dist/stores/SafeSessionStore.d.ts.map +0 -1
- package/dist/stores/SafeSessionStore.js +0 -42
- package/dist/tokenRefresher.d.ts +0 -17
- package/dist/tokenRefresher.d.ts.map +0 -1
- package/dist/tokenRefresher.js +0 -53
- package/dist/tokenStorage.d.ts +0 -15
- package/dist/tokenStorage.d.ts.map +0 -1
- package/dist/tokenStorage.js +0 -107
- package/dist/tokenValidator.d.ts +0 -11
- package/dist/tokenValidator.d.ts.map +0 -1
- package/dist/tokenValidator.js +0 -108
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Common test helpers for AuthBroker tests
|
|
4
|
-
*/
|
|
5
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
-
}
|
|
11
|
-
Object.defineProperty(o, k2, desc);
|
|
12
|
-
}) : (function(o, m, k, k2) {
|
|
13
|
-
if (k2 === undefined) k2 = k;
|
|
14
|
-
o[k2] = m[k];
|
|
15
|
-
}));
|
|
16
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
-
}) : function(o, v) {
|
|
19
|
-
o["default"] = v;
|
|
20
|
-
});
|
|
21
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
-
var ownKeys = function(o) {
|
|
23
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
-
var ar = [];
|
|
25
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
-
return ar;
|
|
27
|
-
};
|
|
28
|
-
return ownKeys(o);
|
|
29
|
-
};
|
|
30
|
-
return function (mod) {
|
|
31
|
-
if (mod && mod.__esModule) return mod;
|
|
32
|
-
var result = {};
|
|
33
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
-
__setModuleDefault(result, mod);
|
|
35
|
-
return result;
|
|
36
|
-
};
|
|
37
|
-
})();
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.TEST_DESTINATIONS_PATH = void 0;
|
|
40
|
-
exports.setupTestBrokers = setupTestBrokers;
|
|
41
|
-
exports.cleanupTestBrokers = cleanupTestBrokers;
|
|
42
|
-
exports.checkNoExistsFile = checkNoExistsFile;
|
|
43
|
-
exports.prepareTest2 = prepareTest2;
|
|
44
|
-
exports.prepareTest3 = prepareTest3;
|
|
45
|
-
exports.verifyEnvFile = verifyEnvFile;
|
|
46
|
-
const path = __importStar(require("path"));
|
|
47
|
-
const os = __importStar(require("os"));
|
|
48
|
-
const fs = __importStar(require("fs"));
|
|
49
|
-
const AuthBroker_1 = require("../AuthBroker");
|
|
50
|
-
const logger_1 = require("../logger");
|
|
51
|
-
const stores_1 = require("../stores");
|
|
52
|
-
// Fixed test destinations path - user can place service keys here
|
|
53
|
-
exports.TEST_DESTINATIONS_PATH = process.env.TEST_DESTINATIONS_PATH || path.join(process.cwd(), 'test-destinations');
|
|
54
|
-
/**
|
|
55
|
-
* Setup test brokers for a test suite
|
|
56
|
-
*/
|
|
57
|
-
function setupTestBrokers(testName) {
|
|
58
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), `auth-broker-${testName}-test-`));
|
|
59
|
-
const broker = new AuthBroker_1.AuthBroker({
|
|
60
|
-
serviceKeyStore: new stores_1.FileServiceKeyStore([tempDir]),
|
|
61
|
-
sessionStore: new stores_1.FileSessionStore([tempDir]),
|
|
62
|
-
}, undefined, logger_1.testLogger);
|
|
63
|
-
const testDestinationsBroker = new AuthBroker_1.AuthBroker({
|
|
64
|
-
serviceKeyStore: new stores_1.FileServiceKeyStore([exports.TEST_DESTINATIONS_PATH]),
|
|
65
|
-
sessionStore: new stores_1.FileSessionStore([exports.TEST_DESTINATIONS_PATH]),
|
|
66
|
-
}, undefined, logger_1.testLogger);
|
|
67
|
-
return { tempDir, broker, testDestinationsBroker };
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Cleanup test brokers
|
|
71
|
-
*/
|
|
72
|
-
function cleanupTestBrokers(brokers) {
|
|
73
|
-
if (brokers.tempDir && fs.existsSync(brokers.tempDir)) {
|
|
74
|
-
fs.rmSync(brokers.tempDir, { recursive: true, force: true });
|
|
75
|
-
}
|
|
76
|
-
brokers.broker.clearAllCache();
|
|
77
|
-
brokers.testDestinationsBroker.clearAllCache();
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Check if NO_EXISTS.json exists and skip test if it does
|
|
81
|
-
*/
|
|
82
|
-
function checkNoExistsFile() {
|
|
83
|
-
const noExistsJson = path.join(exports.TEST_DESTINATIONS_PATH, 'NO_EXISTS.json');
|
|
84
|
-
if (fs.existsSync(noExistsJson)) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Prepare Test 2: Remove TRIAL.env if exists, check for TRIAL.json
|
|
91
|
-
*/
|
|
92
|
-
function prepareTest2() {
|
|
93
|
-
const envFile = path.join(exports.TEST_DESTINATIONS_PATH, 'TRIAL.env');
|
|
94
|
-
const serviceKeyPath = path.join(exports.TEST_DESTINATIONS_PATH, 'TRIAL.json');
|
|
95
|
-
// Remove TRIAL.env if it exists before Test 2
|
|
96
|
-
if (fs.existsSync(envFile)) {
|
|
97
|
-
fs.unlinkSync(envFile);
|
|
98
|
-
}
|
|
99
|
-
// Check if service key exists
|
|
100
|
-
if (!fs.existsSync(serviceKeyPath)) {
|
|
101
|
-
return { envFile, serviceKeyPath, shouldSkip: true };
|
|
102
|
-
}
|
|
103
|
-
return { envFile, serviceKeyPath, shouldSkip: false };
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Prepare Test 3: Check for TRIAL.json and TRIAL.env
|
|
107
|
-
*/
|
|
108
|
-
function prepareTest3() {
|
|
109
|
-
const serviceKeyPath = path.join(exports.TEST_DESTINATIONS_PATH, 'TRIAL.json');
|
|
110
|
-
const envFile = path.join(exports.TEST_DESTINATIONS_PATH, 'TRIAL.env');
|
|
111
|
-
// Check if service key exists
|
|
112
|
-
if (!fs.existsSync(serviceKeyPath)) {
|
|
113
|
-
return { envFile, serviceKeyPath, sapUrl: '', shouldSkip: true };
|
|
114
|
-
}
|
|
115
|
-
// Test 3 requires TRIAL.env file to exist
|
|
116
|
-
if (!fs.existsSync(envFile)) {
|
|
117
|
-
return { envFile, serviceKeyPath, sapUrl: '', shouldSkip: true };
|
|
118
|
-
}
|
|
119
|
-
const serviceKey = JSON.parse(fs.readFileSync(serviceKeyPath, 'utf8'));
|
|
120
|
-
const envContent = fs.readFileSync(envFile, 'utf8');
|
|
121
|
-
// Extract SAP_URL from .env or service key
|
|
122
|
-
const urlMatch = envContent.match(/SAP_URL=(.+)/);
|
|
123
|
-
const sapUrl = urlMatch ? urlMatch[1].trim() : (serviceKey.url || serviceKey.abap?.url || serviceKey.sap_url);
|
|
124
|
-
return { envFile, serviceKeyPath, sapUrl, shouldSkip: false };
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Verify .env file contains required tokens
|
|
128
|
-
*/
|
|
129
|
-
function verifyEnvFile(envFile, requireRefreshToken = false) {
|
|
130
|
-
expect(fs.existsSync(envFile)).toBe(true);
|
|
131
|
-
const envContent = fs.readFileSync(envFile, 'utf8');
|
|
132
|
-
expect(envContent).toContain('SAP_JWT_TOKEN=');
|
|
133
|
-
if (requireRefreshToken) {
|
|
134
|
-
expect(envContent).toContain('SAP_REFRESH_TOKEN=');
|
|
135
|
-
}
|
|
136
|
-
}
|
package/dist/browserAuth.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Browser authentication - OAuth2 flow for obtaining tokens
|
|
3
|
-
*/
|
|
4
|
-
import { ServiceKey } from './types';
|
|
5
|
-
import { Logger } from './logger';
|
|
6
|
-
/**
|
|
7
|
-
* Start browser authentication flow
|
|
8
|
-
* @param serviceKey Service key with UAA configuration
|
|
9
|
-
* @param browser Browser name (chrome, edge, firefox, system, none)
|
|
10
|
-
* @param logger Optional logger instance. If not provided, uses default logger.
|
|
11
|
-
* @returns Promise that resolves to tokens
|
|
12
|
-
*/
|
|
13
|
-
export declare function startBrowserAuth(serviceKey: ServiceKey, browser?: string, logger?: Logger): Promise<{
|
|
14
|
-
accessToken: string;
|
|
15
|
-
refreshToken?: string;
|
|
16
|
-
}>;
|
|
17
|
-
//# sourceMappingURL=browserAuth.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"browserAuth.d.ts","sourceRoot":"","sources":["../src/browserAuth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,MAAM,EAAiB,MAAM,UAAU,CAAC;AA4DjD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,MAAiB,EAC1B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAyMzD"}
|
package/dist/browserAuth.js
DELETED
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Browser authentication - OAuth2 flow for obtaining tokens
|
|
4
|
-
*/
|
|
5
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
-
}
|
|
11
|
-
Object.defineProperty(o, k2, desc);
|
|
12
|
-
}) : (function(o, m, k, k2) {
|
|
13
|
-
if (k2 === undefined) k2 = k;
|
|
14
|
-
o[k2] = m[k];
|
|
15
|
-
}));
|
|
16
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
-
}) : function(o, v) {
|
|
19
|
-
o["default"] = v;
|
|
20
|
-
});
|
|
21
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
-
var ownKeys = function(o) {
|
|
23
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
-
var ar = [];
|
|
25
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
-
return ar;
|
|
27
|
-
};
|
|
28
|
-
return ownKeys(o);
|
|
29
|
-
};
|
|
30
|
-
return function (mod) {
|
|
31
|
-
if (mod && mod.__esModule) return mod;
|
|
32
|
-
var result = {};
|
|
33
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
-
__setModuleDefault(result, mod);
|
|
35
|
-
return result;
|
|
36
|
-
};
|
|
37
|
-
})();
|
|
38
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
-
};
|
|
41
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
exports.startBrowserAuth = startBrowserAuth;
|
|
43
|
-
const http = __importStar(require("http"));
|
|
44
|
-
const child_process = __importStar(require("child_process"));
|
|
45
|
-
const express_1 = __importDefault(require("express"));
|
|
46
|
-
const axios_1 = __importDefault(require("axios"));
|
|
47
|
-
const logger_1 = require("./logger");
|
|
48
|
-
const BROWSER_MAP = {
|
|
49
|
-
chrome: 'chrome',
|
|
50
|
-
edge: 'msedge',
|
|
51
|
-
firefox: 'firefox',
|
|
52
|
-
system: undefined, // system default
|
|
53
|
-
none: null, // no browser, manual URL copy
|
|
54
|
-
};
|
|
55
|
-
/**
|
|
56
|
-
* Get OAuth2 authorization URL
|
|
57
|
-
*/
|
|
58
|
-
function getJwtAuthorizationUrl(serviceKey, port = 3001) {
|
|
59
|
-
const oauthUrl = serviceKey.uaa?.url;
|
|
60
|
-
const clientid = serviceKey.uaa?.clientid;
|
|
61
|
-
const redirectUri = `http://localhost:${port}/callback`;
|
|
62
|
-
if (!oauthUrl || !clientid) {
|
|
63
|
-
throw new Error('Service key missing UAA URL or client ID');
|
|
64
|
-
}
|
|
65
|
-
return `${oauthUrl}/oauth/authorize?client_id=${encodeURIComponent(clientid)}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code`;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Exchange authorization code for tokens
|
|
69
|
-
*/
|
|
70
|
-
async function exchangeCodeForToken(serviceKey, code) {
|
|
71
|
-
const { url, clientid, clientsecret } = serviceKey.uaa;
|
|
72
|
-
const tokenUrl = `${url}/oauth/token`;
|
|
73
|
-
const redirectUri = 'http://localhost:3001/callback';
|
|
74
|
-
const params = new URLSearchParams();
|
|
75
|
-
params.append('grant_type', 'authorization_code');
|
|
76
|
-
params.append('code', code);
|
|
77
|
-
params.append('redirect_uri', redirectUri);
|
|
78
|
-
const authString = Buffer.from(`${clientid}:${clientsecret}`).toString('base64');
|
|
79
|
-
const response = await (0, axios_1.default)({
|
|
80
|
-
method: 'post',
|
|
81
|
-
url: tokenUrl,
|
|
82
|
-
headers: {
|
|
83
|
-
Authorization: `Basic ${authString}`,
|
|
84
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
85
|
-
},
|
|
86
|
-
data: params.toString(),
|
|
87
|
-
});
|
|
88
|
-
if (response.data && response.data.access_token) {
|
|
89
|
-
return {
|
|
90
|
-
accessToken: response.data.access_token,
|
|
91
|
-
refreshToken: response.data.refresh_token,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
throw new Error('Response does not contain access_token');
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Start browser authentication flow
|
|
100
|
-
* @param serviceKey Service key with UAA configuration
|
|
101
|
-
* @param browser Browser name (chrome, edge, firefox, system, none)
|
|
102
|
-
* @param logger Optional logger instance. If not provided, uses default logger.
|
|
103
|
-
* @returns Promise that resolves to tokens
|
|
104
|
-
*/
|
|
105
|
-
async function startBrowserAuth(serviceKey, browser = 'system', logger) {
|
|
106
|
-
const log = logger || logger_1.defaultLogger;
|
|
107
|
-
return new Promise((originalResolve, originalReject) => {
|
|
108
|
-
let timeoutId = null;
|
|
109
|
-
const resolve = (value) => {
|
|
110
|
-
if (timeoutId)
|
|
111
|
-
clearTimeout(timeoutId);
|
|
112
|
-
originalResolve(value);
|
|
113
|
-
};
|
|
114
|
-
const reject = (reason) => {
|
|
115
|
-
if (timeoutId)
|
|
116
|
-
clearTimeout(timeoutId);
|
|
117
|
-
originalReject(reason);
|
|
118
|
-
};
|
|
119
|
-
const app = (0, express_1.default)();
|
|
120
|
-
const server = http.createServer(app);
|
|
121
|
-
const PORT = 3001;
|
|
122
|
-
let serverInstance = null;
|
|
123
|
-
const authorizationUrl = getJwtAuthorizationUrl(serviceKey, PORT);
|
|
124
|
-
// OAuth2 callback handler
|
|
125
|
-
app.get('/callback', async (req, res) => {
|
|
126
|
-
try {
|
|
127
|
-
const { code } = req.query;
|
|
128
|
-
if (!code || typeof code !== 'string') {
|
|
129
|
-
res.status(400).send('Error: Authorization code missing');
|
|
130
|
-
return reject(new Error('Authorization code missing'));
|
|
131
|
-
}
|
|
132
|
-
// Send success page
|
|
133
|
-
const html = `<!DOCTYPE html>
|
|
134
|
-
<html lang="en">
|
|
135
|
-
<head>
|
|
136
|
-
<meta charset="UTF-8">
|
|
137
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
138
|
-
<title>SAP BTP Authentication</title>
|
|
139
|
-
<style>
|
|
140
|
-
body {
|
|
141
|
-
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
142
|
-
text-align: center;
|
|
143
|
-
margin: 0;
|
|
144
|
-
padding: 50px 20px;
|
|
145
|
-
background: linear-gradient(135deg, #0070f3 0%, #00d4ff 100%);
|
|
146
|
-
color: white;
|
|
147
|
-
min-height: 100vh;
|
|
148
|
-
display: flex;
|
|
149
|
-
flex-direction: column;
|
|
150
|
-
justify-content: center;
|
|
151
|
-
align-items: center;
|
|
152
|
-
}
|
|
153
|
-
.container {
|
|
154
|
-
background: rgba(255, 255, 255, 0.1);
|
|
155
|
-
border-radius: 20px;
|
|
156
|
-
padding: 40px;
|
|
157
|
-
backdrop-filter: blur(10px);
|
|
158
|
-
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
|
159
|
-
max-width: 500px;
|
|
160
|
-
width: 100%;
|
|
161
|
-
}
|
|
162
|
-
.success-icon {
|
|
163
|
-
font-size: 4rem;
|
|
164
|
-
margin-bottom: 20px;
|
|
165
|
-
color: #4ade80;
|
|
166
|
-
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
|
167
|
-
}
|
|
168
|
-
h1 {
|
|
169
|
-
margin: 0 0 20px 0;
|
|
170
|
-
font-size: 2rem;
|
|
171
|
-
font-weight: 300;
|
|
172
|
-
}
|
|
173
|
-
p {
|
|
174
|
-
margin: 0;
|
|
175
|
-
font-size: 1.1rem;
|
|
176
|
-
opacity: 0.9;
|
|
177
|
-
line-height: 1.5;
|
|
178
|
-
}
|
|
179
|
-
</style>
|
|
180
|
-
</head>
|
|
181
|
-
<body>
|
|
182
|
-
<div class="container">
|
|
183
|
-
<div class="success-icon">✓</div>
|
|
184
|
-
<h1>Authentication Successful!</h1>
|
|
185
|
-
<p>You have successfully authenticated with SAP BTP.</p>
|
|
186
|
-
<p>You can now close this browser window.</p>
|
|
187
|
-
</div>
|
|
188
|
-
</body>
|
|
189
|
-
</html>`;
|
|
190
|
-
// Send success page first
|
|
191
|
-
res.send(html);
|
|
192
|
-
// Exchange code for tokens and close server
|
|
193
|
-
try {
|
|
194
|
-
const tokens = await exchangeCodeForToken(serviceKey, code);
|
|
195
|
-
// Close all connections and server immediately after getting tokens
|
|
196
|
-
if (typeof server.closeAllConnections === 'function') {
|
|
197
|
-
server.closeAllConnections();
|
|
198
|
-
}
|
|
199
|
-
server.close(() => {
|
|
200
|
-
// Server closed
|
|
201
|
-
});
|
|
202
|
-
resolve(tokens);
|
|
203
|
-
}
|
|
204
|
-
catch (error) {
|
|
205
|
-
if (typeof server.closeAllConnections === 'function') {
|
|
206
|
-
server.closeAllConnections();
|
|
207
|
-
}
|
|
208
|
-
server.close(() => {
|
|
209
|
-
// Server closed on error
|
|
210
|
-
});
|
|
211
|
-
reject(error);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
catch (error) {
|
|
215
|
-
res.status(500).send('Error processing authentication');
|
|
216
|
-
server.close(() => {
|
|
217
|
-
// Server closed on error
|
|
218
|
-
});
|
|
219
|
-
reject(error);
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
serverInstance = server.listen(PORT, async () => {
|
|
223
|
-
const browserApp = BROWSER_MAP[browser];
|
|
224
|
-
if (!browser || browser === 'none' || browserApp === null) {
|
|
225
|
-
log.browserUrl(authorizationUrl);
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
log.browserOpening();
|
|
229
|
-
try {
|
|
230
|
-
// Try dynamic import first (for ES modules)
|
|
231
|
-
let open;
|
|
232
|
-
try {
|
|
233
|
-
const openModule = await Promise.resolve().then(() => __importStar(require('open')));
|
|
234
|
-
open = openModule.default;
|
|
235
|
-
}
|
|
236
|
-
catch (importError) {
|
|
237
|
-
// Fallback: use child_process to open browser if import fails
|
|
238
|
-
// This works in both CommonJS and ES module environments (like Jest)
|
|
239
|
-
const platform = process.platform;
|
|
240
|
-
let command;
|
|
241
|
-
if (browserApp === 'chrome') {
|
|
242
|
-
command = platform === 'win32'
|
|
243
|
-
? 'start chrome'
|
|
244
|
-
: platform === 'darwin'
|
|
245
|
-
? 'open -a "Google Chrome"'
|
|
246
|
-
: 'google-chrome';
|
|
247
|
-
}
|
|
248
|
-
else if (browserApp === 'edge') {
|
|
249
|
-
command = platform === 'win32'
|
|
250
|
-
? 'start msedge'
|
|
251
|
-
: platform === 'darwin'
|
|
252
|
-
? 'open -a "Microsoft Edge"'
|
|
253
|
-
: 'microsoft-edge';
|
|
254
|
-
}
|
|
255
|
-
else if (browserApp === 'firefox') {
|
|
256
|
-
command = platform === 'win32'
|
|
257
|
-
? 'start firefox'
|
|
258
|
-
: platform === 'darwin'
|
|
259
|
-
? 'open -a Firefox'
|
|
260
|
-
: 'firefox';
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
// System default
|
|
264
|
-
command = platform === 'win32'
|
|
265
|
-
? 'start'
|
|
266
|
-
: platform === 'darwin'
|
|
267
|
-
? 'open'
|
|
268
|
-
: 'xdg-open';
|
|
269
|
-
}
|
|
270
|
-
// Use child_process as fallback (non-blocking)
|
|
271
|
-
child_process.exec(`${command} "${authorizationUrl}"`, (error) => {
|
|
272
|
-
if (error) {
|
|
273
|
-
log.error(`❌ Failed to open browser: ${error.message}. Please open manually: ${authorizationUrl}`);
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
return; // Exit early since we're using child_process (non-blocking)
|
|
277
|
-
}
|
|
278
|
-
// Use open module if import succeeded
|
|
279
|
-
if (browserApp) {
|
|
280
|
-
await open(authorizationUrl, { app: { name: browserApp } });
|
|
281
|
-
}
|
|
282
|
-
else {
|
|
283
|
-
await open(authorizationUrl);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
catch (error) {
|
|
287
|
-
// If browser cannot be opened, show URL and throw error for consumer to catch
|
|
288
|
-
log.error(`❌ Failed to open browser: ${error?.message || String(error)}. Please open manually: ${authorizationUrl}`);
|
|
289
|
-
log.browserUrl(authorizationUrl);
|
|
290
|
-
// Throw error so consumer can distinguish this from "service key missing" error
|
|
291
|
-
reject(new Error(`Browser opening failed for destination authentication. Please open manually: ${authorizationUrl}`));
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
});
|
|
295
|
-
// Timeout after 5 minutes
|
|
296
|
-
timeoutId = setTimeout(() => {
|
|
297
|
-
if (serverInstance) {
|
|
298
|
-
server.close(() => {
|
|
299
|
-
// Server closed on timeout
|
|
300
|
-
});
|
|
301
|
-
reject(new Error('Authentication timeout. Process aborted.'));
|
|
302
|
-
}
|
|
303
|
-
}, 5 * 60 * 1000);
|
|
304
|
-
});
|
|
305
|
-
}
|
package/dist/cache.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Token cache management
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Get cached token for destination
|
|
6
|
-
*/
|
|
7
|
-
export declare function getCachedToken(destination: string): string | null;
|
|
8
|
-
/**
|
|
9
|
-
* Set cached token for destination
|
|
10
|
-
*/
|
|
11
|
-
export declare function setCachedToken(destination: string, token: string, expiresAt?: number): void;
|
|
12
|
-
/**
|
|
13
|
-
* Clear cached token for destination
|
|
14
|
-
*/
|
|
15
|
-
export declare function clearCache(destination: string): void;
|
|
16
|
-
/**
|
|
17
|
-
* Clear all cached tokens
|
|
18
|
-
*/
|
|
19
|
-
export declare function clearAllCache(): void;
|
|
20
|
-
//# sourceMappingURL=cache.d.ts.map
|
package/dist/cache.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH;;GAEG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAajE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAK3F;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}
|
package/dist/cache.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Token cache management
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getCachedToken = getCachedToken;
|
|
7
|
-
exports.setCachedToken = setCachedToken;
|
|
8
|
-
exports.clearCache = clearCache;
|
|
9
|
-
exports.clearAllCache = clearAllCache;
|
|
10
|
-
const tokenCache = new Map();
|
|
11
|
-
/**
|
|
12
|
-
* Get cached token for destination
|
|
13
|
-
*/
|
|
14
|
-
function getCachedToken(destination) {
|
|
15
|
-
const cached = tokenCache.get(destination);
|
|
16
|
-
if (!cached) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
// Check if token is expired (if expiration time is set)
|
|
20
|
-
if (cached.expiresAt && Date.now() >= cached.expiresAt) {
|
|
21
|
-
tokenCache.delete(destination);
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
return cached.token;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Set cached token for destination
|
|
28
|
-
*/
|
|
29
|
-
function setCachedToken(destination, token, expiresAt) {
|
|
30
|
-
tokenCache.set(destination, {
|
|
31
|
-
token,
|
|
32
|
-
expiresAt,
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Clear cached token for destination
|
|
37
|
-
*/
|
|
38
|
-
function clearCache(destination) {
|
|
39
|
-
tokenCache.delete(destination);
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Clear all cached tokens
|
|
43
|
-
*/
|
|
44
|
-
function clearAllCache() {
|
|
45
|
-
tokenCache.clear();
|
|
46
|
-
}
|
package/dist/envLoader.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Environment file loader - loads .env files by destination name
|
|
3
|
-
*/
|
|
4
|
-
import { EnvConfig } from './types';
|
|
5
|
-
/**
|
|
6
|
-
* Load environment configuration from {destination}.env file
|
|
7
|
-
* @param destination Destination name
|
|
8
|
-
* @param searchPaths Array of paths to search for the file
|
|
9
|
-
* @returns EnvConfig object or null if file not found
|
|
10
|
-
*/
|
|
11
|
-
export declare function loadEnvFile(destination: string, searchPaths: string[]): Promise<EnvConfig | null>;
|
|
12
|
-
//# sourceMappingURL=envLoader.d.ts.map
|
package/dist/envLoader.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"envLoader.d.ts","sourceRoot":"","sources":["../src/envLoader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAqDvG"}
|
package/dist/envLoader.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Environment file loader - loads .env files by destination name
|
|
4
|
-
*/
|
|
5
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
-
}
|
|
11
|
-
Object.defineProperty(o, k2, desc);
|
|
12
|
-
}) : (function(o, m, k, k2) {
|
|
13
|
-
if (k2 === undefined) k2 = k;
|
|
14
|
-
o[k2] = m[k];
|
|
15
|
-
}));
|
|
16
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
-
}) : function(o, v) {
|
|
19
|
-
o["default"] = v;
|
|
20
|
-
});
|
|
21
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
-
var ownKeys = function(o) {
|
|
23
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
-
var ar = [];
|
|
25
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
-
return ar;
|
|
27
|
-
};
|
|
28
|
-
return ownKeys(o);
|
|
29
|
-
};
|
|
30
|
-
return function (mod) {
|
|
31
|
-
if (mod && mod.__esModule) return mod;
|
|
32
|
-
var result = {};
|
|
33
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
-
__setModuleDefault(result, mod);
|
|
35
|
-
return result;
|
|
36
|
-
};
|
|
37
|
-
})();
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.loadEnvFile = loadEnvFile;
|
|
40
|
-
const fs = __importStar(require("fs"));
|
|
41
|
-
const dotenv = __importStar(require("dotenv"));
|
|
42
|
-
const pathResolver_1 = require("./pathResolver");
|
|
43
|
-
/**
|
|
44
|
-
* Load environment configuration from {destination}.env file
|
|
45
|
-
* @param destination Destination name
|
|
46
|
-
* @param searchPaths Array of paths to search for the file
|
|
47
|
-
* @returns EnvConfig object or null if file not found
|
|
48
|
-
*/
|
|
49
|
-
async function loadEnvFile(destination, searchPaths) {
|
|
50
|
-
const fileName = `${destination}.env`;
|
|
51
|
-
const envFilePath = (0, pathResolver_1.findFileInPaths)(fileName, searchPaths);
|
|
52
|
-
if (!envFilePath) {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
try {
|
|
56
|
-
// Read and parse .env file
|
|
57
|
-
const envContent = fs.readFileSync(envFilePath, 'utf8');
|
|
58
|
-
const parsed = dotenv.parse(envContent);
|
|
59
|
-
// Extract required fields
|
|
60
|
-
const sapUrl = parsed.SAP_URL;
|
|
61
|
-
const jwtToken = parsed.SAP_JWT_TOKEN;
|
|
62
|
-
if (!sapUrl || !jwtToken) {
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
const config = {
|
|
66
|
-
sapUrl: sapUrl.trim(),
|
|
67
|
-
jwtToken: jwtToken.trim(),
|
|
68
|
-
};
|
|
69
|
-
// Optional fields
|
|
70
|
-
if (parsed.SAP_CLIENT) {
|
|
71
|
-
config.sapClient = parsed.SAP_CLIENT.trim();
|
|
72
|
-
}
|
|
73
|
-
if (parsed.SAP_REFRESH_TOKEN) {
|
|
74
|
-
config.refreshToken = parsed.SAP_REFRESH_TOKEN.trim();
|
|
75
|
-
}
|
|
76
|
-
if (parsed.SAP_UAA_URL) {
|
|
77
|
-
config.uaaUrl = parsed.SAP_UAA_URL.trim();
|
|
78
|
-
}
|
|
79
|
-
if (parsed.SAP_UAA_CLIENT_ID) {
|
|
80
|
-
config.uaaClientId = parsed.SAP_UAA_CLIENT_ID.trim();
|
|
81
|
-
}
|
|
82
|
-
if (parsed.SAP_UAA_CLIENT_SECRET) {
|
|
83
|
-
config.uaaClientSecret = parsed.SAP_UAA_CLIENT_SECRET.trim();
|
|
84
|
-
}
|
|
85
|
-
return config;
|
|
86
|
-
}
|
|
87
|
-
catch (error) {
|
|
88
|
-
throw new Error(`Failed to load environment file for destination "${destination}": ${error instanceof Error ? error.message : String(error)}`);
|
|
89
|
-
}
|
|
90
|
-
}
|
package/dist/getToken.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Get token implementation - loads from .env, validates, refreshes if needed
|
|
3
|
-
*/
|
|
4
|
-
import { Logger } from './logger';
|
|
5
|
-
/**
|
|
6
|
-
* Get authentication token for destination
|
|
7
|
-
* @param destination Destination name
|
|
8
|
-
* @param searchPaths Array of paths to search for files
|
|
9
|
-
* @param logger Optional logger instance. If not provided, uses default logger.
|
|
10
|
-
* @returns JWT token string
|
|
11
|
-
* @throws Error if neither .env file nor service key found
|
|
12
|
-
*/
|
|
13
|
-
export declare function getToken(destination: string, searchPaths: string[], logger?: Logger): Promise<string>;
|
|
14
|
-
//# sourceMappingURL=getToken.d.ts.map
|
package/dist/getToken.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getToken.d.ts","sourceRoot":"","sources":["../src/getToken.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,OAAO,EAAE,MAAM,EAAiB,MAAM,UAAU,CAAC;AAEjD;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA8C3G"}
|