Merge pull request #15769 from Budibase/BUDI-9127/validate
Validate config
This commit is contained in:
commit
67543dbe7d
|
@ -49,5 +49,5 @@
|
||||||
</ActionMenu>
|
</ActionMenu>
|
||||||
|
|
||||||
<Modal bind:this={modal}>
|
<Modal bind:this={modal}>
|
||||||
<OAuth2ConfigModalContent config={row} />
|
<OAuth2ConfigModalContent config={{ ...row }} />
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -70,12 +70,28 @@
|
||||||
return keepOpen
|
return keepOpen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { data: configData } = validationResult
|
||||||
try {
|
try {
|
||||||
|
const connectionValidation = await oauth2.validate({
|
||||||
|
id: config?.id,
|
||||||
|
url: configData.url,
|
||||||
|
clientId: configData.clientId,
|
||||||
|
clientSecret: configData.clientSecret,
|
||||||
|
})
|
||||||
|
if (!connectionValidation.valid) {
|
||||||
|
let message = "Connection settings could not be validated"
|
||||||
|
if (connectionValidation.message) {
|
||||||
|
message += `: ${connectionValidation.message}`
|
||||||
|
}
|
||||||
|
notifications.error(message)
|
||||||
|
return keepOpen
|
||||||
|
}
|
||||||
|
|
||||||
if (isCreation) {
|
if (isCreation) {
|
||||||
await oauth2.create(validationResult.data)
|
await oauth2.create(configData)
|
||||||
notifications.success("Settings created.")
|
notifications.success("Settings created.")
|
||||||
} else {
|
} else {
|
||||||
await oauth2.edit(config!.id, validationResult.data)
|
await oauth2.edit(config!.id, configData)
|
||||||
notifications.success("Settings saved.")
|
notifications.success("Settings saved.")
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { API } from "@/api"
|
import { API } from "@/api"
|
||||||
import { BudiStore } from "@/stores/BudiStore"
|
import { BudiStore } from "@/stores/BudiStore"
|
||||||
import { OAuth2Config, UpsertOAuth2Config } from "@/types"
|
import { OAuth2Config, UpsertOAuth2Config } from "@/types"
|
||||||
|
import { ValidateConfigRequest } from "@budibase/types"
|
||||||
|
|
||||||
interface OAuth2StoreState {
|
interface OAuth2StoreState {
|
||||||
configs: OAuth2Config[]
|
configs: OAuth2Config[]
|
||||||
|
@ -57,6 +58,10 @@ export class OAuth2Store extends BudiStore<OAuth2StoreState> {
|
||||||
await API.oauth2.delete(id)
|
await API.oauth2.delete(id)
|
||||||
await this.fetch()
|
await this.fetch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async validate(config: ValidateConfigRequest) {
|
||||||
|
return await API.oauth2.validate(config)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const oauth2 = new OAuth2Store()
|
export const oauth2 = new OAuth2Store()
|
||||||
|
|
|
@ -3,6 +3,8 @@ import {
|
||||||
OAuth2ConfigResponse,
|
OAuth2ConfigResponse,
|
||||||
UpsertOAuth2ConfigRequest,
|
UpsertOAuth2ConfigRequest,
|
||||||
UpsertOAuth2ConfigResponse,
|
UpsertOAuth2ConfigResponse,
|
||||||
|
ValidateConfigRequest,
|
||||||
|
ValidateConfigResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { BaseAPIClient } from "./types"
|
import { BaseAPIClient } from "./types"
|
||||||
|
|
||||||
|
@ -16,6 +18,7 @@ export interface OAuth2Endpoints {
|
||||||
config: UpsertOAuth2ConfigRequest
|
config: UpsertOAuth2ConfigRequest
|
||||||
) => Promise<UpsertOAuth2ConfigResponse>
|
) => Promise<UpsertOAuth2ConfigResponse>
|
||||||
delete: (id: string) => Promise<void>
|
delete: (id: string) => Promise<void>
|
||||||
|
validate: (config: ValidateConfigRequest) => Promise<ValidateConfigResponse>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const buildOAuth2Endpoints = (API: BaseAPIClient): OAuth2Endpoints => ({
|
export const buildOAuth2Endpoints = (API: BaseAPIClient): OAuth2Endpoints => ({
|
||||||
|
@ -32,8 +35,6 @@ export const buildOAuth2Endpoints = (API: BaseAPIClient): OAuth2Endpoints => ({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a OAuth2 configuration.
|
* Creates a OAuth2 configuration.
|
||||||
* @param name the name of the row action
|
|
||||||
* @param tableId the ID of the table
|
|
||||||
*/
|
*/
|
||||||
create: async config => {
|
create: async config => {
|
||||||
return await API.post<
|
return await API.post<
|
||||||
|
@ -49,8 +50,6 @@ export const buildOAuth2Endpoints = (API: BaseAPIClient): OAuth2Endpoints => ({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates an existing OAuth2 configuration.
|
* Updates an existing OAuth2 configuration.
|
||||||
* @param name the name of the row action
|
|
||||||
* @param tableId the ID of the table
|
|
||||||
*/
|
*/
|
||||||
update: async (id, config) => {
|
update: async (id, config) => {
|
||||||
return await API.put<UpsertOAuth2ConfigRequest, UpsertOAuth2ConfigResponse>(
|
return await API.put<UpsertOAuth2ConfigRequest, UpsertOAuth2ConfigResponse>(
|
||||||
|
@ -72,4 +71,14 @@ export const buildOAuth2Endpoints = (API: BaseAPIClient): OAuth2Endpoints => ({
|
||||||
url: `/api/oauth2/${id}`,
|
url: `/api/oauth2/${id}`,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
validate: async function (
|
||||||
|
config: ValidateConfigRequest
|
||||||
|
): Promise<ValidateConfigResponse> {
|
||||||
|
return await API.post<ValidateConfigRequest, ValidateConfigResponse>({
|
||||||
|
url: `/api/oauth2/validate`,
|
||||||
|
body: {
|
||||||
|
...config,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -7,6 +7,8 @@ import {
|
||||||
RequiredKeys,
|
RequiredKeys,
|
||||||
OAuth2ConfigResponse,
|
OAuth2ConfigResponse,
|
||||||
PASSWORD_REPLACEMENT,
|
PASSWORD_REPLACEMENT,
|
||||||
|
ValidateConfigResponse,
|
||||||
|
ValidateConfigRequest,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import sdk from "../../sdk"
|
import sdk from "../../sdk"
|
||||||
|
|
||||||
|
@ -75,3 +77,27 @@ export async function remove(
|
||||||
await sdk.oauth2.remove(configToRemove)
|
await sdk.oauth2.remove(configToRemove)
|
||||||
ctx.status = 204
|
ctx.status = 204
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function validate(
|
||||||
|
ctx: Ctx<ValidateConfigRequest, ValidateConfigResponse>
|
||||||
|
) {
|
||||||
|
const { body } = ctx.request
|
||||||
|
const config = {
|
||||||
|
url: body.url,
|
||||||
|
clientId: body.clientId,
|
||||||
|
clientSecret: body.clientSecret,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.clientSecret === PASSWORD_REPLACEMENT && body.id) {
|
||||||
|
const existingConfig = await sdk.oauth2.get(body.id)
|
||||||
|
if (!existingConfig) {
|
||||||
|
ctx.throw(`OAuth2 config with id '${body.id}' not found.`, 404)
|
||||||
|
}
|
||||||
|
|
||||||
|
config.clientSecret = existingConfig.clientSecret
|
||||||
|
}
|
||||||
|
|
||||||
|
const validation = await sdk.oauth2.validateConfig(config)
|
||||||
|
ctx.status = 201
|
||||||
|
ctx.body = validation
|
||||||
|
}
|
||||||
|
|
|
@ -38,5 +38,10 @@ router.delete(
|
||||||
authorized(PermissionType.BUILDER),
|
authorized(PermissionType.BUILDER),
|
||||||
controller.remove
|
controller.remove
|
||||||
)
|
)
|
||||||
|
router.post(
|
||||||
|
"/api/oauth2/validate",
|
||||||
|
authorized(PermissionType.BUILDER),
|
||||||
|
controller.validate
|
||||||
|
)
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|
|
@ -31,3 +31,34 @@ export async function generateToken(id: string) {
|
||||||
|
|
||||||
return `${jsonResponse.token_type} ${jsonResponse.access_token}`
|
return `${jsonResponse.token_type} ${jsonResponse.access_token}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function validateConfig(config: {
|
||||||
|
url: string
|
||||||
|
clientId: string
|
||||||
|
clientSecret: string
|
||||||
|
}): Promise<{ valid: boolean; message?: string }> {
|
||||||
|
try {
|
||||||
|
const resp = await fetch(config.url, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({
|
||||||
|
grant_type: "client_credentials",
|
||||||
|
client_id: config.clientId,
|
||||||
|
client_secret: config.clientSecret,
|
||||||
|
}),
|
||||||
|
redirect: "follow",
|
||||||
|
})
|
||||||
|
|
||||||
|
const jsonResponse = await resp.json()
|
||||||
|
if (!resp.ok) {
|
||||||
|
const message = jsonResponse.error_description ?? resp.statusText
|
||||||
|
return { valid: false, message }
|
||||||
|
}
|
||||||
|
|
||||||
|
return { valid: true }
|
||||||
|
} catch (e: any) {
|
||||||
|
return { valid: false, message: e.message }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,3 +20,15 @@ export interface UpsertOAuth2ConfigRequest {
|
||||||
export interface UpsertOAuth2ConfigResponse {
|
export interface UpsertOAuth2ConfigResponse {
|
||||||
config: OAuth2ConfigResponse
|
config: OAuth2ConfigResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ValidateConfigRequest {
|
||||||
|
id?: string
|
||||||
|
url: string
|
||||||
|
clientId: string
|
||||||
|
clientSecret: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ValidateConfigResponse {
|
||||||
|
valid: boolean
|
||||||
|
message?: string
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue