11import axios from 'axios' ;
2- import { wrapper } from 'axios-cookiejar-support' ;
3- import https from 'https' ;
4- import { sym , literal } from 'rdflib' ;
2+ import { sym } from 'rdflib' ;
53import * as $rdf from "rdflib" ;
6- import { DOMParser } from '@xmldom/xmldom' ;
7- import { CookieJar , Cookie } from 'tough-cookie' ;
8- import { rdf , dcterms , rdfs , oslc , oslc_cm1 , oslc_rm , oslc_qm1 } from './namespaces.js' ;
4+ import { rdfs , oslc , oslc_cm1 , oslc_rm , oslc_qm1 } from './namespaces.js' ;
95import OSLCResource from './OSLCResource.js' ;
106import Compact from './Compact.js' ;
117import RootServices from './RootServices.js' ;
128import ServiceProviderCatalog from './ServiceProviderCatalog.js' ;
139import ServiceProvider from './ServiceProvider.js' ;
1410
11+ // Conditional imports for Node.js only
12+ let wrapper , CookieJar , DOMParser ;
13+ const isNodeEnvironment = typeof window === 'undefined' ;
14+
15+ if ( isNodeEnvironment ) {
16+ // Node.js imports
17+ const cookiejarSupport = await import ( 'axios-cookiejar-support' ) ;
18+ wrapper = cookiejarSupport . wrapper ;
19+ const toughCookie = await import ( 'tough-cookie' ) ;
20+ CookieJar = toughCookie . CookieJar ;
21+ const xmldom = await import ( '@xmldom/xmldom' ) ;
22+ DOMParser = xmldom . DOMParser ;
23+ } else {
24+ // Browser: use native DOMParser
25+ DOMParser = window . DOMParser ;
26+ }
27+
1528// Service providers properties
1629const serviceProviders = {
1730 'CM' : oslc_cm1 ( 'cmServiceProviders' ) ,
@@ -35,31 +48,34 @@ export default class OSLCClient {
3548 this . spc = null ;
3649 this . sp = null ;
3750 this . ownerMap = new Map ( ) ;
38- this . jar = new CookieJar ( ) ;
51+ this . isNodeEnvironment = isNodeEnvironment ;
52+
53+ if ( isNodeEnvironment ) {
54+ this . jar = new CookieJar ( ) ;
55+ }
3956
4057 // Create a base configuration
4158 const baseConfig = {
4259 timeout : 30000 ,
43- keepAlive : true ,
4460 headers : {
4561 'Accept' : 'application/rdf+xml, text/turtle;q=0.9, application/ld+json;q=0.8, application/json;q=0.7, application/xml;q=0.6, text/xml;q=0.5, */*;q=0.1' ,
4662 'OSLC-Core-Version' : '2.0'
4763 } ,
4864 validateStatus : status => status === 401 || status < 400 // Accept all 2xx responses
4965 } ;
5066
51- // Check if we're in Node.js (where 'window' is undefined)
52- if ( typeof window === 'undefined' ) {
53- // We are in Node.js -> use a cookie jar
67+ // Configure for Node.js or Browser
68+ if ( isNodeEnvironment ) {
69+ // Node.js: use a cookie jar and keep-alive
70+ baseConfig . keepAlive = true ;
5471 baseConfig . jar = this . jar ;
72+ this . client = wrapper ( axios . create ( baseConfig ) ) ;
5573 } else {
56- // We are in the Browser -> use withCredentials
74+ // Browser: use withCredentials for automatic cookie handling
5775 baseConfig . withCredentials = true ;
76+ this . client = axios . create ( baseConfig ) ;
5877 }
5978
60- // Create axios instance with cookie agents
61- this . client = wrapper ( axios . create ( baseConfig ) ) ;
62-
6379 // Add the Configuration-Context header if one is given
6480 if ( configuration_context ) {
6581 this . client . defaults . headers . common [ 'Configuration-Context' ] = configuration_context ;
@@ -70,37 +86,35 @@ export default class OSLCClient {
7086 async response => {
7187 const originalRequest = response . config ;
7288 const wwwAuthenticate = response ?. headers ?. [ 'www-authenticate' ] ;
73- /*
74- const allCookies = await originalRequest.jar.store.getAllCookies();
75- console.log('\n--- ALL COOKIES IN JAR ---');
76- allCookies.forEach((cookie, index) => {
77- console.log(`\n[${index + 1}] ${cookie.key}=${cookie.value}`);
78- console.log(` Domain: ${cookie.domain}`);
79- console.log(` Path: ${cookie.path}`);
80- console.log(` Expires: ${cookie.expires}`);
81- console.log(` HTTP Only: ${cookie.httpOnly}`);
82- console.log(` Secure: ${cookie.secure}`);
83- });
84- */
89+
8590 // Check if this is a JEE Forms authentication challenge
8691 if ( response ?. headers [ 'x-com-ibm-team-repository-web-auth-msg' ] === 'authrequired' ) {
8792 try {
8893 // Perform the login (JEE form auth typically uses j_username and j_password)
8994 let url = new URL ( response . config . url ) ;
9095 const paths = url . pathname . split ( '/' ) ;
9196 url . pathname = paths [ 1 ] ? `/${ paths [ 1 ] } /j_security_check` : '/j_security_check' ;
92- response = await this . client . post ( url . toString ( ) , {
93- 'j_username' : this . userid ,
94- 'j_password' : this . password
95- } , {
96- headers : {
97- 'Content-Type' : 'application/x-www-form-urlencoded'
98- } ,
99- maxRedirects : 0 ,
100- validateStatus : ( status ) => status === 302 // for successful login
101- } ) ;
97+
98+ // In browser, form-based auth may require a backend proxy due to CORS
99+ if ( ! isNodeEnvironment ) {
100+ console . warn ( 'Form-based authentication in browser requires CORS-enabled backend or proxy' ) ;
101+ }
102+
103+ response = await this . client . post ( url . toString ( ) ,
104+ new URLSearchParams ( {
105+ 'j_username' : this . userid ,
106+ 'j_password' : this . password
107+ } ) . toString ( ) ,
108+ {
109+ headers : {
110+ 'Content-Type' : 'application/x-www-form-urlencoded'
111+ } ,
112+ maxRedirects : 0 ,
113+ validateStatus : ( status ) => status === 302 // for successful login
114+ }
115+ ) ;
102116 // After successful login, retry the original request with updated cookies
103- response = await this . client ( originalRequest ) ;
117+ response = await this . client . request ( originalRequest ) ;
104118 return response ;
105119 } catch ( error ) {
106120 console . error ( 'Error during JEE authentication:' , error . message ) ;
@@ -110,30 +124,33 @@ export default class OSLCClient {
110124 const token_uri = wwwAuthenticate . match ( / t o k e n _ u r i = " ( [ ^ " ] + ) " / ) [ 1 ] ;
111125 try {
112126 // Refresh the token using the provided token_uri
113- const response = await axios . post ( token_uri ,
114- new URLSearchParams ( {
115- username : this . userid ,
116- password : this . password ,
117- } ) , {
118- headers : {
119- 'Content-Type' : 'application/x-www-form-urlencoded' ,
120- 'Accept' : 'test/plain' ,
121- } } ) ;
127+ const tokenResponse = await this . client . post ( token_uri ,
128+ new URLSearchParams ( {
129+ username : this . userid ,
130+ password : this . password ,
131+ } ) . toString ( ) ,
132+ {
133+ headers : {
134+ 'Content-Type' : 'application/x-www-form-urlencoded' ,
135+ 'Accept' : 'text/plain' ,
136+ }
137+ }
138+ ) ;
122139 // retry the original request with the new token
123- const newToken = response . data ; // Refresh token
124- originalRequest . config . headers [ 'Authorization' ] = `Bearer ${ newToken } ` ;
125- return await axios . client ( originalRequest ) ; // Retry the request
140+ const newToken = tokenResponse . data ; // Refresh token
141+ originalRequest . headers [ 'Authorization' ] = `Bearer ${ newToken } ` ;
142+ return await this . client . request ( originalRequest ) ; // Retry the request
126143 } catch ( error ) {
127144 console . error ( 'Error during jauth realm authentication:' , error . message ) ;
128145 return Promise . reject ( error ) ;
129146 }
130147 } else if ( response . status === 401 ) {
131- // Retry with basic authentication for e.g., Jazz Authorizaiton Server
132- response . config . auth = {
148+ // Retry with basic authentication for e.g., Jazz Authorization Server
149+ originalRequest . auth = {
133150 username : this . userid ,
134151 password : this . password
135152 } ;
136- return await axios . request ( response . config ) ;
153+ return await this . client . request ( originalRequest ) ;
137154 } else {
138155 // No authentication challenge, proceed with the response
139156 return response ;
@@ -322,8 +339,23 @@ export default class OSLCClient {
322339 const headers = {
323340 'Accept' : 'application/rdf+xml; charset=utf-8' ,
324341 'OSLC-Core-Version' : oslc_version ,
325- 'X-Jazz-CSRF-Prevent' : this . jar . getCookiesSync ( url ) . find ( cookie => cookie . key === 'JSESSIONID' ) . value
342+ 'X-Jazz-CSRF-Prevent' : '1'
326343 } ;
344+
345+ // In Node.js, try to get JSESSIONID from cookie jar
346+ if ( isNodeEnvironment && this . jar ) {
347+ try {
348+ const cookies = this . jar . getCookiesSync ( url ) ;
349+ const sessionCookie = cookies . find ( cookie => cookie . key === 'JSESSIONID' ) ;
350+ if ( sessionCookie ) {
351+ headers [ 'X-Jazz-CSRF-Prevent' ] = sessionCookie . value ;
352+ }
353+ } catch ( error ) {
354+ // If cookie retrieval fails, continue with default value
355+ console . debug ( 'Could not retrieve JSESSIONID from cookie jar:' , error . message ) ;
356+ }
357+ }
358+
327359 try {
328360 const response = await this . client . delete ( url , { headers } ) ;
329361 if ( response . status !== 200 && response . status !== 204 ) {
@@ -410,7 +442,8 @@ export default class OSLCClient {
410442 if ( response . status !== 200 ) {
411443 return 'Unknown' ;
412444 }
413- const contentLocation = response . headers [ 'content-location' ] || url ;
445+ const contentLocation = response . headers [ 'content-location' ] || url ;
446+ const contentType = response . headers [ 'content-type' ] ;
414447 const store = $rdf . graph ( ) ;
415448 try {
416449 $rdf . parse ( response . data , store , url , contentType )
0 commit comments