mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-07 04:20:05 +00:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb88376bda | ||
|
|
4c8ddeca25 | ||
|
|
d264a3f239 | ||
|
|
840b1aa1bf | ||
|
|
e26fd307c8 | ||
|
|
62deaf9f03 | ||
|
|
865bf71f7d | ||
|
|
734c5bccaa | ||
|
|
bc82cb5f5e | ||
|
|
f25c76fdfd | ||
|
|
e649b41e9e | ||
|
|
a962979765 | ||
| 9dc0499f66 | |||
|
|
bc1a7dc54f | ||
|
|
93c267fd4e | ||
|
|
de5c38f0fb | ||
|
|
208470e7d9 | ||
|
|
ff4915f7f3 | ||
|
|
6ff8eece7b | ||
|
|
2849e6ed07 | ||
|
|
7f590c35da | ||
|
|
e975e7de97 | ||
|
|
f0ecfa57e5 |
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
@@ -13,14 +13,15 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [15.x]
|
node-version: [lts/fermium]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
|
cache: npm
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
- name: Check code style
|
- name: Check code style
|
||||||
|
|||||||
19879
package-lock.json
generated
19879
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@@ -41,30 +41,34 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/axios": "^0.14.0",
|
"@types/axios": "^0.14.0",
|
||||||
|
"@types/express": "^4.17.13",
|
||||||
"@types/form-data": "^2.5.0",
|
"@types/form-data": "^2.5.0",
|
||||||
"@types/jest": "^27.0.1",
|
"@types/jest": "^27.0.2",
|
||||||
"@types/mime": "^2.0.3",
|
"@types/mime": "^2.0.3",
|
||||||
|
"@types/pem": "^1.9.6",
|
||||||
"@types/tough-cookie": "^4.0.1",
|
"@types/tough-cookie": "^4.0.1",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"cp": "^0.2.0",
|
"cp": "^0.2.0",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
|
"express": "^4.17.1",
|
||||||
"jest": "^27.2.0",
|
"jest": "^27.2.0",
|
||||||
"jest-extended": "^0.11.5",
|
"jest-extended": "^0.11.5",
|
||||||
"node-polyfill-webpack-plugin": "^1.1.4",
|
"node-polyfill-webpack-plugin": "^1.1.4",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
|
"pem": "^1.14.4",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"semantic-release": "^17.4.7",
|
"semantic-release": "^18.0.0",
|
||||||
"terser-webpack-plugin": "^5.2.4",
|
"terser-webpack-plugin": "^5.2.4",
|
||||||
"ts-jest": "^27.0.3",
|
"ts-jest": "^27.0.3",
|
||||||
"ts-loader": "^9.2.2",
|
"ts-loader": "^9.2.6",
|
||||||
"tslint": "^6.1.3",
|
"tslint": "^6.1.3",
|
||||||
"tslint-config-prettier": "^1.18.0",
|
"tslint-config-prettier": "^1.18.0",
|
||||||
"typedoc": "^0.22.3",
|
"typedoc": "^0.22.4",
|
||||||
"typedoc-neo-theme": "^1.1.1",
|
"typedoc-neo-theme": "^1.1.1",
|
||||||
"typedoc-plugin-external-module-name": "^4.0.6",
|
"typedoc-plugin-external-module-name": "^4.0.6",
|
||||||
"typescript": "4.3.5",
|
"typescript": "4.3.5",
|
||||||
"webpack": "^5.52.1",
|
"webpack": "^5.56.0",
|
||||||
"webpack-cli": "^4.7.2"
|
"webpack-cli": "^4.7.2"
|
||||||
},
|
},
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ const defaultConfig: SASjsConfig = {
|
|||||||
debug: false,
|
debug: false,
|
||||||
contextName: 'SAS Job Execution compute context',
|
contextName: 'SAS Job Execution compute context',
|
||||||
useComputeApi: false,
|
useComputeApi: false,
|
||||||
allowInsecureRequests: false,
|
|
||||||
loginMechanism: LoginMechanism.Default
|
loginMechanism: LoginMechanism.Default
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import * as https from 'https'
|
||||||
import { generateTimestamp } from '@sasjs/utils/time'
|
import { generateTimestamp } from '@sasjs/utils/time'
|
||||||
import * as NodeFormData from 'form-data'
|
import * as NodeFormData from 'form-data'
|
||||||
import { Sas9RequestClient } from './request/Sas9RequestClient'
|
import { Sas9RequestClient } from './request/Sas9RequestClient'
|
||||||
@@ -13,10 +14,10 @@ export class SAS9ApiClient {
|
|||||||
constructor(
|
constructor(
|
||||||
private serverUrl: string,
|
private serverUrl: string,
|
||||||
private jobsPath: string,
|
private jobsPath: string,
|
||||||
allowInsecureRequests: boolean
|
httpsAgentOptions?: https.AgentOptions
|
||||||
) {
|
) {
|
||||||
if (serverUrl) isUrl(serverUrl)
|
if (serverUrl) isUrl(serverUrl)
|
||||||
this.requestClient = new Sas9RequestClient(serverUrl, allowInsecureRequests)
|
this.requestClient = new Sas9RequestClient(serverUrl, httpsAgentOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
13
src/SASjs.ts
13
src/SASjs.ts
@@ -40,7 +40,6 @@ const defaultConfig: SASjsConfig = {
|
|||||||
debug: false,
|
debug: false,
|
||||||
contextName: 'SAS Job Execution compute context',
|
contextName: 'SAS Job Execution compute context',
|
||||||
useComputeApi: null,
|
useComputeApi: null,
|
||||||
allowInsecureRequests: false,
|
|
||||||
loginMechanism: LoginMechanism.Default
|
loginMechanism: LoginMechanism.Default
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +61,7 @@ export default class SASjs {
|
|||||||
private jesJobExecutor: JobExecutor | null = null
|
private jesJobExecutor: JobExecutor | null = null
|
||||||
private sas9JobExecutor: JobExecutor | null = null
|
private sas9JobExecutor: JobExecutor | null = null
|
||||||
|
|
||||||
constructor(config?: any) {
|
constructor(config?: Partial<SASjsConfig>) {
|
||||||
this.sasjsConfig = {
|
this.sasjsConfig = {
|
||||||
...defaultConfig,
|
...defaultConfig,
|
||||||
...config
|
...config
|
||||||
@@ -797,7 +796,7 @@ export default class SASjs {
|
|||||||
sasApiClient = new SAS9ApiClient(
|
sasApiClient = new SAS9ApiClient(
|
||||||
serverUrl,
|
serverUrl,
|
||||||
this.jobsPath,
|
this.jobsPath,
|
||||||
this.sasjsConfig.allowInsecureRequests
|
this.sasjsConfig.httpsAgentOptions
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -964,12 +963,12 @@ export default class SASjs {
|
|||||||
if (!this.requestClient) {
|
if (!this.requestClient) {
|
||||||
this.requestClient = new RequestClient(
|
this.requestClient = new RequestClient(
|
||||||
this.sasjsConfig.serverUrl,
|
this.sasjsConfig.serverUrl,
|
||||||
this.sasjsConfig.allowInsecureRequests
|
this.sasjsConfig.httpsAgentOptions
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
this.requestClient.setConfig(
|
this.requestClient.setConfig(
|
||||||
this.sasjsConfig.serverUrl,
|
this.sasjsConfig.serverUrl,
|
||||||
this.sasjsConfig.allowInsecureRequests
|
this.sasjsConfig.httpsAgentOptions
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1010,7 +1009,7 @@ export default class SASjs {
|
|||||||
this.sas9ApiClient = new SAS9ApiClient(
|
this.sas9ApiClient = new SAS9ApiClient(
|
||||||
this.sasjsConfig.serverUrl,
|
this.sasjsConfig.serverUrl,
|
||||||
this.jobsPath,
|
this.jobsPath,
|
||||||
this.sasjsConfig.allowInsecureRequests
|
this.sasjsConfig.httpsAgentOptions
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1045,7 +1044,7 @@ export default class SASjs {
|
|||||||
this.sasjsConfig.serverUrl,
|
this.sasjsConfig.serverUrl,
|
||||||
this.sasjsConfig.serverType!,
|
this.sasjsConfig.serverType!,
|
||||||
this.jobsPath,
|
this.jobsPath,
|
||||||
this.sasjsConfig.allowInsecureRequests
|
this.sasjsConfig.httpsAgentOptions
|
||||||
)
|
)
|
||||||
|
|
||||||
this.computeJobExecutor = new ComputeJobExecutor(
|
this.computeJobExecutor = new ComputeJobExecutor(
|
||||||
|
|||||||
@@ -256,7 +256,9 @@ export class AuthManager {
|
|||||||
.split(' ')
|
.split(' ')
|
||||||
.map((name: string) => name.slice(0, 3).toLowerCase())
|
.map((name: string) => name.slice(0, 3).toLowerCase())
|
||||||
.join('')
|
.join('')
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
console.error('Server Type not found in extractUserName function')
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export async function getAccessToken(
|
|||||||
)
|
)
|
||||||
.then((res) => res.result as SasAuthResponse)
|
.then((res) => res.result as SasAuthResponse)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw prefixMessage(err, 'Error while getting access token')
|
throw prefixMessage(err, 'Error while getting access token. ')
|
||||||
})
|
})
|
||||||
|
|
||||||
return authResponse
|
return authResponse
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import * as https from 'https'
|
||||||
import { ServerType } from '@sasjs/utils/types'
|
import { ServerType } from '@sasjs/utils/types'
|
||||||
import * as NodeFormData from 'form-data'
|
import * as NodeFormData from 'form-data'
|
||||||
import { ErrorResponse } from '../types/errors'
|
import { ErrorResponse } from '../types/errors'
|
||||||
@@ -17,10 +18,10 @@ export class Sas9JobExecutor extends BaseJobExecutor {
|
|||||||
serverUrl: string,
|
serverUrl: string,
|
||||||
serverType: ServerType,
|
serverType: ServerType,
|
||||||
private jobsPath: string,
|
private jobsPath: string,
|
||||||
allowInsecureRequests: boolean
|
httpsAgentOptions?: https.AgentOptions
|
||||||
) {
|
) {
|
||||||
super(serverUrl, serverType)
|
super(serverUrl, serverType)
|
||||||
this.requestClient = new Sas9RequestClient(serverUrl, allowInsecureRequests)
|
this.requestClient = new Sas9RequestClient(serverUrl, httpsAgentOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(sasJob: string, data: any, config: any) {
|
async execute(sasJob: string, data: any, config: any) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
|
import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
|
||||||
|
import * as https from 'https'
|
||||||
import { CsrfToken } from '..'
|
import { CsrfToken } from '..'
|
||||||
import { isAuthorizeFormRequired, isLogInRequired } from '../auth'
|
import { isAuthorizeFormRequired, isLogInRequired } from '../auth'
|
||||||
import {
|
import {
|
||||||
@@ -12,7 +13,11 @@ import { SASjsRequest } from '../types'
|
|||||||
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
||||||
import { prefixMessage } from '@sasjs/utils/error'
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
import { SAS9AuthError } from '../types/errors/SAS9AuthError'
|
import { SAS9AuthError } from '../types/errors/SAS9AuthError'
|
||||||
import { parseGeneratedCode, parseSourceCode } from '../utils'
|
import {
|
||||||
|
parseGeneratedCode,
|
||||||
|
parseSourceCode,
|
||||||
|
createAxiosInstance
|
||||||
|
} from '../utils'
|
||||||
|
|
||||||
export interface HttpClient {
|
export interface HttpClient {
|
||||||
get<T>(
|
get<T>(
|
||||||
@@ -54,12 +59,15 @@ export class RequestClient implements HttpClient {
|
|||||||
protected fileUploadCsrfToken: CsrfToken | undefined
|
protected fileUploadCsrfToken: CsrfToken | undefined
|
||||||
protected httpClient!: AxiosInstance
|
protected httpClient!: AxiosInstance
|
||||||
|
|
||||||
constructor(protected baseUrl: string, allowInsecure = false) {
|
constructor(
|
||||||
this.createHttpClient(baseUrl, allowInsecure)
|
protected baseUrl: string,
|
||||||
|
httpsAgentOptions?: https.AgentOptions
|
||||||
|
) {
|
||||||
|
this.createHttpClient(baseUrl, httpsAgentOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
public setConfig(baseUrl: string, allowInsecure = false) {
|
public setConfig(baseUrl: string, httpsAgentOptions?: https.AgentOptions) {
|
||||||
this.createHttpClient(baseUrl, allowInsecure)
|
this.createHttpClient(baseUrl, httpsAgentOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCsrfToken(type: 'general' | 'file' = 'general') {
|
public getCsrfToken(type: 'general' | 'file' = 'general') {
|
||||||
@@ -511,20 +519,15 @@ export class RequestClient implements HttpClient {
|
|||||||
return responseToReturn
|
return responseToReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
private createHttpClient(baseUrl: string, allowInsecure = false) {
|
private createHttpClient(
|
||||||
const https = require('https')
|
baseUrl: string,
|
||||||
if (allowInsecure && https.Agent) {
|
httpsAgentOptions?: https.AgentOptions
|
||||||
this.httpClient = axios.create({
|
) {
|
||||||
baseURL: baseUrl,
|
const httpsAgent = httpsAgentOptions
|
||||||
httpsAgent: new https.Agent({
|
? new https.Agent(httpsAgentOptions)
|
||||||
rejectUnauthorized: !allowInsecure
|
: undefined
|
||||||
})
|
|
||||||
})
|
this.httpClient = createAxiosInstance(baseUrl, httpsAgent)
|
||||||
} else {
|
|
||||||
this.httpClient = axios.create({
|
|
||||||
baseURL: baseUrl
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
this.httpClient.defaults.validateStatus = (status) =>
|
this.httpClient.defaults.validateStatus = (status) =>
|
||||||
status >= 200 && status < 401
|
status >= 200 && status < 401
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import * as https from 'https'
|
||||||
import { AxiosRequestConfig } from 'axios'
|
import { AxiosRequestConfig } from 'axios'
|
||||||
import axiosCookieJarSupport from 'axios-cookiejar-support'
|
import axiosCookieJarSupport from 'axios-cookiejar-support'
|
||||||
import * as tough from 'tough-cookie'
|
import * as tough from 'tough-cookie'
|
||||||
@@ -9,8 +10,8 @@ import { RequestClient, throwIfError } from './RequestClient'
|
|||||||
* Handles redirects and cookie management.
|
* Handles redirects and cookie management.
|
||||||
*/
|
*/
|
||||||
export class Sas9RequestClient extends RequestClient {
|
export class Sas9RequestClient extends RequestClient {
|
||||||
constructor(baseUrl: string, allowInsecure = false) {
|
constructor(baseUrl: string, httpsAgentOptions?: https.AgentOptions) {
|
||||||
super(baseUrl, allowInsecure)
|
super(baseUrl, httpsAgentOptions)
|
||||||
this.httpClient.defaults.maxRedirects = 0
|
this.httpClient.defaults.maxRedirects = 0
|
||||||
this.httpClient.defaults.validateStatus = (status) =>
|
this.httpClient.defaults.validateStatus = (status) =>
|
||||||
status >= 200 && status < 303
|
status >= 200 && status < 303
|
||||||
|
|||||||
167
src/test/RequestClient.spec.ts
Normal file
167
src/test/RequestClient.spec.ts
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
import * as pem from 'pem'
|
||||||
|
import * as http from 'http'
|
||||||
|
import * as https from 'https'
|
||||||
|
import { app, mockedAuthResponse } from './SAS_server_app'
|
||||||
|
import { ServerType } from '@sasjs/utils'
|
||||||
|
import SASjs from '../SASjs'
|
||||||
|
import * as axiosModules from '../utils/createAxiosInstance'
|
||||||
|
|
||||||
|
const axiosActual = jest.requireActual('axios')
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(axiosModules, 'createAxiosInstance')
|
||||||
|
.mockImplementation((baseURL: string, httpsAgent?: https.Agent) =>
|
||||||
|
axiosActual.create({ baseURL, httpsAgent })
|
||||||
|
)
|
||||||
|
|
||||||
|
const PORT = 8000
|
||||||
|
const SERVER_URL = `https://localhost:${PORT}/`
|
||||||
|
|
||||||
|
const ERROR_MESSAGES = {
|
||||||
|
selfSigned: 'self signed certificate',
|
||||||
|
CCA: 'unable to verify the first certificate'
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('RequestClient', () => {
|
||||||
|
let server: http.Server
|
||||||
|
|
||||||
|
const adapter = new SASjs({
|
||||||
|
serverUrl: `http://localhost:${PORT}/`,
|
||||||
|
serverType: ServerType.SasViya
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await new Promise((resolve: any, reject: any) => {
|
||||||
|
server = app
|
||||||
|
.listen(PORT, () => resolve())
|
||||||
|
.on('error', (err: any) => reject(err))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
server.close()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should response the POST method', async () => {
|
||||||
|
const authResponse = await adapter.getAccessToken(
|
||||||
|
'clientId',
|
||||||
|
'clientSecret',
|
||||||
|
'authCode'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(authResponse.access_token).toBe(mockedAuthResponse.access_token)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should response the POST method with Unauthorized', async () => {
|
||||||
|
await expect(
|
||||||
|
adapter.getAccessToken('clientId', 'clientSecret', 'incorrect')
|
||||||
|
).rejects.toThrow(
|
||||||
|
'Error while getting access token. Request failed with status code 401'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('RequestClient - Self Signed Server', () => {
|
||||||
|
let adapter: SASjs
|
||||||
|
|
||||||
|
let httpsServer: https.Server
|
||||||
|
let sslConfig: pem.CertificateCreationResult
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
;({ httpsServer, keys: sslConfig } = await setupSelfSignedServer())
|
||||||
|
await new Promise((resolve: any, reject: any) => {
|
||||||
|
httpsServer
|
||||||
|
.listen(PORT, () => resolve())
|
||||||
|
.on('error', (err: any) => reject(err))
|
||||||
|
})
|
||||||
|
|
||||||
|
adapter = new SASjs({
|
||||||
|
serverUrl: SERVER_URL,
|
||||||
|
serverType: ServerType.SasViya,
|
||||||
|
httpsAgentOptions: { ca: [sslConfig.certificate] }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
httpsServer.close()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error for not providing certificate', async () => {
|
||||||
|
const adapterWithoutCertificate = new SASjs({
|
||||||
|
serverUrl: SERVER_URL,
|
||||||
|
serverType: ServerType.SasViya
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
adapterWithoutCertificate.getAccessToken(
|
||||||
|
'clientId',
|
||||||
|
'clientSecret',
|
||||||
|
'authCode'
|
||||||
|
)
|
||||||
|
).rejects.toThrow(
|
||||||
|
`Error while getting access token. ${ERROR_MESSAGES.selfSigned}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should response the POST method using insecure flag', async () => {
|
||||||
|
const adapterAllowInsecure = new SASjs({
|
||||||
|
serverUrl: SERVER_URL,
|
||||||
|
serverType: ServerType.SasViya,
|
||||||
|
httpsAgentOptions: { rejectUnauthorized: false }
|
||||||
|
})
|
||||||
|
|
||||||
|
const authResponse = await adapterAllowInsecure.getAccessToken(
|
||||||
|
'clientId',
|
||||||
|
'clientSecret',
|
||||||
|
'authCode'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(authResponse.access_token).toBe(mockedAuthResponse.access_token)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should response the POST method', async () => {
|
||||||
|
const authResponse = await adapter.getAccessToken(
|
||||||
|
'clientId',
|
||||||
|
'clientSecret',
|
||||||
|
'authCode'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(authResponse.access_token).toBe(mockedAuthResponse.access_token)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should response the POST method with Unauthorized', async () => {
|
||||||
|
await expect(
|
||||||
|
adapter.getAccessToken('clientId', 'clientSecret', 'incorrect')
|
||||||
|
).rejects.toThrow(
|
||||||
|
'Error while getting access token. Request failed with status code 401'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const setupSelfSignedServer = async (): Promise<{
|
||||||
|
httpsServer: https.Server
|
||||||
|
keys: pem.CertificateCreationResult
|
||||||
|
}> => {
|
||||||
|
return await new Promise(async (resolve) => {
|
||||||
|
const keys = await createCertificate()
|
||||||
|
|
||||||
|
const httpsServer = https.createServer(
|
||||||
|
{ key: keys.clientKey, cert: keys.certificate },
|
||||||
|
app
|
||||||
|
)
|
||||||
|
|
||||||
|
resolve({ httpsServer, keys })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const createCertificate = async (): Promise<pem.CertificateCreationResult> => {
|
||||||
|
return await new Promise((resolve, reject) => {
|
||||||
|
pem.createCertificate(
|
||||||
|
{ days: 1, selfSigned: true },
|
||||||
|
(error: any, keys: pem.CertificateCreationResult) => {
|
||||||
|
if (error) reject(false)
|
||||||
|
resolve(keys)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
38
src/test/SAS_server_app.ts
Normal file
38
src/test/SAS_server_app.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import express = require('express')
|
||||||
|
|
||||||
|
export const app = express()
|
||||||
|
|
||||||
|
export const mockedAuthResponse = {
|
||||||
|
access_token: 'access_token',
|
||||||
|
token_type: 'bearer',
|
||||||
|
id_token: 'id_token',
|
||||||
|
refresh_token: 'refresh_token',
|
||||||
|
expires_in: 43199,
|
||||||
|
scope: 'openid',
|
||||||
|
jti: 'jti'
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get('/', function (req: any, res: any) {
|
||||||
|
res.send('Hello World')
|
||||||
|
})
|
||||||
|
|
||||||
|
app.post('/SASLogon/oauth/token', function (req: any, res: any) {
|
||||||
|
let valid = true
|
||||||
|
// capture the encoded form data
|
||||||
|
req.on('data', (data: any) => {
|
||||||
|
const resData = data.toString()
|
||||||
|
|
||||||
|
if (resData.includes('incorrect')) valid = false
|
||||||
|
})
|
||||||
|
|
||||||
|
// send a response when finished reading
|
||||||
|
// the encoded form data
|
||||||
|
req.on('end', () => {
|
||||||
|
if (valid) res.status(200).send(mockedAuthResponse)
|
||||||
|
else
|
||||||
|
res.status(401).send({
|
||||||
|
error: 'unauthorized',
|
||||||
|
error_description: 'Bad credentials'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import { SessionManager } from '../SessionManager'
|
import { SessionManager } from '../SessionManager'
|
||||||
import { RequestClient } from '../request/RequestClient'
|
import { RequestClient } from '../request/RequestClient'
|
||||||
import { NoSessionStateError } from '../types/errors'
|
|
||||||
import * as dotenv from 'dotenv'
|
import * as dotenv from 'dotenv'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { Logger, LogLevel } from '@sasjs/utils'
|
import { Logger, LogLevel } from '@sasjs/utils'
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
export interface ExecutionQuery {
|
export interface ExecutionQuery {
|
||||||
_program: string
|
_program: string
|
||||||
_debug?: number
|
_debug?: number
|
||||||
_log?: boolean
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import * as https from 'https'
|
||||||
import { ServerType } from '@sasjs/utils/types'
|
import { ServerType } from '@sasjs/utils/types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,11 +55,11 @@ export class SASjsConfig {
|
|||||||
*/
|
*/
|
||||||
useComputeApi: boolean | null = null
|
useComputeApi: boolean | null = null
|
||||||
/**
|
/**
|
||||||
* Defaults to `false`.
|
* Optional settings to configure HTTPS Agent.
|
||||||
* When set to `true`, the adapter will allow requests to SAS servers that use a self-signed SSL certificate.
|
* By providing `key`, `cert`, `ca` to connect with server
|
||||||
* Changing this setting is not recommended.
|
* Other options can be set `rejectUnauthorized` and `requestCert`
|
||||||
*/
|
*/
|
||||||
allowInsecureRequests = false
|
httpsAgentOptions?: https.AgentOptions
|
||||||
/**
|
/**
|
||||||
* Supported login mechanisms are - Redirected and Default
|
* Supported login mechanisms are - Redirected and Default
|
||||||
*/
|
*/
|
||||||
|
|||||||
7
src/utils/createAxiosInstance.ts
Normal file
7
src/utils/createAxiosInstance.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
import * as https from 'https'
|
||||||
|
|
||||||
|
export const createAxiosInstance = (
|
||||||
|
baseURL: string,
|
||||||
|
httpsAgent?: https.Agent
|
||||||
|
) => axios.create({ baseURL, httpsAgent })
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
export * from './asyncForEach'
|
export * from './asyncForEach'
|
||||||
export * from './compareTimestamps'
|
export * from './compareTimestamps'
|
||||||
export * from './convertToCsv'
|
export * from './convertToCsv'
|
||||||
|
export * from './createAxiosInstance'
|
||||||
export * from './delay'
|
export * from './delay'
|
||||||
export * from './isNode'
|
export * from './isNode'
|
||||||
export * from './isRelativePath'
|
export * from './isRelativePath'
|
||||||
|
|||||||
Reference in New Issue
Block a user