Skip to content

Commit

Permalink
fix(shared): Stop using jquery (for ajax and selection) (closes #76) (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
grgrzybek authored Sep 12, 2024
1 parent 54f0784 commit f1809c5
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 135 deletions.
18 changes: 12 additions & 6 deletions packages/hawtio/src/core/config-manager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import $ from 'jquery'
import { Plugin } from './core'
import { Logger } from './logging'

Expand Down Expand Up @@ -192,14 +191,21 @@ class ConfigManager {

private updateHref(id: string, path: string, moveToLast: boolean = false): void {
log.info('Updating href for', id, '-', path, moveToLast)
const elm = $(id)
elm.prop('disabled', true)
elm.attr({ href: path })
const elm = document.querySelector(id) as HTMLInputElement
if (!elm) {
return
}
if ('disabled' in elm) {
elm.disabled = true
}
elm.setAttribute('href', path)
if (moveToLast) {
elm.remove()
$('head').append(elm)
document.querySelector('head')?.append(elm)
}
if ('disabled' in elm) {
elm.disabled = false
}
elm.prop('disabled', false)
}

async isRouteEnabled(path: string): Promise<boolean> {
Expand Down
7 changes: 3 additions & 4 deletions packages/hawtio/src/core/core.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { userService } from '@hawtiosrc/auth'
import { importRemote, ImportRemoteOptions } from '@module-federation/utilities'
import $ from 'jquery'
import { configManager } from './config-manager'
import { eventService } from './event-service'
import { log } from './globals'
Expand Down Expand Up @@ -162,9 +161,9 @@ class HawtioCore {
}

private documentBase(): string | undefined {
const base = $('head').find('base')
if (base && base.length > 0) {
return base.attr('href')
const base = document.querySelector('head base')
if (base) {
return base.getAttribute('href') ?? undefined
}
return undefined
}
Expand Down
56 changes: 0 additions & 56 deletions packages/hawtio/src/plugins/auth/keycloak/keycloak-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { userService } from '@hawtiosrc/auth'
import { ResolveUser } from '@hawtiosrc/auth/user-service'
import { fetchPath } from '@hawtiosrc/util/fetch'
import { basicAuthHeaderValue, getCookie } from '@hawtiosrc/util/https'
import $ from 'jquery'
import Keycloak, { KeycloakConfig, KeycloakInitOptions, KeycloakPkceMethod, KeycloakProfile } from 'keycloak-js'
import { UserProfile } from '../types'
import { PATH_KEYCLOAK_CLIENT_CONFIG, PATH_KEYCLOAK_ENABLED, PATH_KEYCLOAK_VALIDATE, log } from './globals'
Expand Down Expand Up @@ -139,7 +138,6 @@ class KeycloakService implements IKeycloakService {
userService.setToken(userProfile.token)
}

this.setupJQueryAjax()
this.setupFetch()

return true
Expand All @@ -163,60 +161,6 @@ class KeycloakService implements IKeycloakService {
userService.addLogoutHook('keycloak', logout)
}

private async setupJQueryAjax() {
const keycloak = await this.keycloak
const config = await this.config
if (!keycloak || !config) {
return
}

log.debug('Set authorization header to Keycloak token for AJAX requests')
const beforeSend = (xhr: JQueryXHR, settings: JQueryAjaxSettings) => {
const logPrefix = 'jQuery -'
if (!keycloak.authenticated || keycloak.isTokenExpired(KEYCLOAK_TOKEN_MINIMUM_VALIDITY)) {
log.debug(logPrefix, 'Try to update token for request:', settings.url)
this.updateToken(
token => {
if (token) {
log.debug(logPrefix, 'Keycloak token refreshed. Set new value to userService')
userService.setToken(token)
}
log.debug(logPrefix, 'Re-sending request after successfully updating Keycloak token:', settings.url)
$.ajax(settings)
},
() => {
log.debug(logPrefix, 'Logging out due to token update failed')
userService.logout()
},
)
return false
}

if (config.jaas) {
// Use BearerTokenLoginModule on server side
if (keycloak.profile && keycloak.profile.username && keycloak.token) {
const headerValue = basicAuthHeaderValue(keycloak.profile.username, keycloak.token)
xhr.setRequestHeader('Authorization', headerValue)
} else {
log.error(logPrefix, 'Keycloak username or token not found in JAAS mode:', keycloak.profile, keycloak.token)
}
} else {
// Otherwise, bearer token is used
xhr.setRequestHeader('Authorization', `Bearer ${keycloak.token}`)
}

// For CSRF protection with Spring Security
const token = getCookie('XSRF-TOKEN')
if (token) {
log.debug(logPrefix, 'Set XSRF token header from cookies')
xhr.setRequestHeader('X-XSRF-TOKEN', token)
}

return // To suppress ts(7030)
}
$.ajaxSetup({ beforeSend })
}

private async setupFetch() {
const keycloak = await this.keycloak
const config = await this.config
Expand Down
45 changes: 0 additions & 45 deletions packages/hawtio/src/plugins/auth/oidc/oidc-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { jwtDecode } from 'jwt-decode'
import * as oidc from 'oauth4webapi'
import { AuthorizationServer, Client, OAuth2Error } from 'oauth4webapi'
import { fetchPath } from '@hawtiosrc/util/fetch'
import $ from 'jquery'
import { getCookie } from '@hawtiosrc/util/https'

const pluginName = 'hawtio-oidc'
Expand Down Expand Up @@ -285,7 +284,6 @@ export class OidcService implements IOidcService {
// clear the URL bar
window.history.replaceState(null, '', loginData.h)

this.setupJQueryAjax()
this.setupFetch()

return {
Expand Down Expand Up @@ -385,49 +383,6 @@ export class OidcService implements IOidcService {
}
}

private async setupJQueryAjax() {
let userInfo = await this.userInfo
if (!userInfo) {
return
}

log.debug('Set authorization header to OIDC token for AJAX requests')
const beforeSend = (xhr: JQueryXHR, settings: JQueryAjaxSettings) => {
const logPrefix = 'jQuery -'
if (userInfo && (!userInfo.access_token || this.isTokenExpiring(userInfo.at_exp))) {
log.debug(logPrefix, 'Try to update token for request:', settings.url)
this.updateToken(
_userInfo => {
if (_userInfo) {
userInfo = _userInfo
log.debug(logPrefix, 'OIDC token refreshed. Set new value to userService')
userService.setToken(userInfo.access_token!)
}
log.debug(logPrefix, 'Re-sending request after successfully updating OIDC token:', settings.url)
$.ajax(settings)
},
() => {
log.debug(logPrefix, 'Logging out due to token update failed')
userService.logout()
},
)
return false
}

xhr.setRequestHeader('Authorization', `Bearer ${userInfo!.access_token}`)

// For CSRF protection with Spring Security
const token = getCookie('XSRF-TOKEN')
if (token) {
log.debug(logPrefix, 'Set XSRF token header from cookies')
xhr.setRequestHeader('X-XSRF-TOKEN', token)
}

return // To suppress ts(7030)
}
$.ajaxSetup({ beforeSend })
}

private async setupFetch() {
let userInfo = await this.userInfo
if (!userInfo) {
Expand Down
46 changes: 24 additions & 22 deletions packages/hawtio/src/plugins/shared/jolokia-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import {
WriteResponseValue,
} from 'jolokia.js'
import Jolokia, { IJolokiaSimple, SimpleRequestOptions, SimpleResponseCallback } from '@jolokia.js/simple'
import $ from 'jquery'
import { is, object } from 'superstruct'
import {
PARAM_KEY_CONNECTION,
Expand Down Expand Up @@ -258,35 +257,38 @@ class JolokiaService implements IJolokiaService {
// browser popup)
// TOCHECK: scenarios when there's no server side session (Keycloak, OIDC)
return new Promise<string>((resolve, reject) => {
$.ajax(path)
.done((data: string, _textStatus: string, xhr: JQueryXHR) => {
if (xhr.status !== 200) {
reject()
return
}

try {
const resp = typeof data === 'string' ? JSON.parse(data) : data
if ('value' in resp && 'agent' in resp.value) {
log.debug('Found jolokia agent at:', path, ', version:', resp.value.agent)
resolve(path)
fetch(path)
.then(async (response: Response) => {
// for fetch(), .then() is fed with any response code, while .catch() is used to handle
// more serious issues (like connection refused)
if (response.status == 200) {
try {
const resp = await response.json()
if ('value' in resp && 'agent' in resp.value) {
log.debug('Found jolokia agent at:', path, ', version:', resp.value.agent)
resolve(path)
return
}
} catch (e) {
// Parse error should mean redirect to html
reject(e)
return
}
} catch (e) {
// Parse error should mean redirect to html
reject(e)
reject()
return
}
reject()
})
.fail((xhr: JQueryXHR) => {
if (xhr.status === 401 || xhr.status === 403) {
if (response.status === 401 || response.status === 403) {
// I guess this could be it...
log.debug('Using URL:', path, 'assuming it could be an agent but got return code:', xhr.status)
log.debug('Using URL:', path, 'assuming it could be an agent but got return code:', response.status)
resolve(path)
return
}
reject(`${xhr.status} ${xhr.statusText}`)
reject()
return
})
.catch(error => {
reject(error)
return
})
})
}
Expand Down
2 changes: 0 additions & 2 deletions packages/hawtio/src/setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import '@testing-library/jest-dom'
import crypto from 'crypto'
import fetchMock from 'jest-fetch-mock'
import $ from 'jquery'
import { TextDecoder, TextEncoder } from 'util'

fetchMock.enableMocks()
Expand All @@ -27,7 +26,6 @@ fetchMock.mockResponse(req => {
// To fix "jQuery is not defined" error
// eslint-disable-next-line @typescript-eslint/no-explicit-any
declare const global: any
global.$ = global.jQuery = $

// For testing crypto
Object.defineProperty(global, 'crypto', { value: crypto.webcrypto })
Expand Down

0 comments on commit f1809c5

Please sign in to comment.