-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
254 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import colors from 'colors/safe.js'; | ||
|
||
import { Logger } from '../logger.js'; | ||
import { findAddonsByNameOrId } from '../models/ids-resolver.js'; | ||
import { genBiscuitsKeypair, getBiscuitsKeypair, getBiscuitsKeyPairTemplate, protectRoute } from '../models/otoroshi-biscuits.js'; | ||
import { getBiscuitKeypairs } from '../models/otoroshi-instances-api.js'; | ||
import { getOtoroshiApiParams, sendToOtoroshi } from '../models/otoroshi.js'; | ||
|
||
export async function get (params) { | ||
const [keypairId, addonIdOrName] = params.args; | ||
const { format } = params.options; | ||
const keypair = await getBiscuitsKeypair(addonIdOrName, keypairId); | ||
|
||
switch (format) { | ||
case 'json': | ||
Logger.printJson(keypair); | ||
break; | ||
case 'human': | ||
default: | ||
console.table(keypair); | ||
break; | ||
} | ||
} | ||
|
||
export async function protect (params) { | ||
const [addonIdOrName, route, destination] = params.args; | ||
await protectRoute(addonIdOrName, route, destination); | ||
} | ||
|
||
export async function keypairsList (params) { | ||
const [addonIdOrName] = params.args; | ||
const [otoroshi] = await findAddonsByNameOrId(addonIdOrName.addon_name); | ||
|
||
const otoroshiConfig = await getOtoroshiApiParams(otoroshi.realId); | ||
const keypairs = await getBiscuitKeypairs(otoroshiConfig).then(sendToOtoroshi); | ||
|
||
keypairs.forEach((k) => { | ||
console.table(k); | ||
}); | ||
} | ||
|
||
export async function keygen (params) { | ||
const [addonIdOrName] = params.args; | ||
|
||
const template = await getBiscuitsKeyPairTemplate(addonIdOrName); | ||
|
||
template.name = 'Biscuit CT Key Pair'; | ||
template.description = 'A new Biscuit key pair created from Clever Tools'; | ||
|
||
const keypair = await genBiscuitsKeypair(addonIdOrName, template); | ||
|
||
Logger.println(`🔑 New key pair successfully generated for Otoroshi add-on ${colors.blue(addonIdOrName.addon_name)}`); | ||
Logger.println(` └─ Public key: ${colors.green(keypair.pubKey)}`); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { enableWaf } from '../models/waf.js'; | ||
|
||
export async function enable (params) { | ||
const [addonIdOrName, route, destination] = params.args; | ||
|
||
await enableWaf(addonIdOrName, route, destination); | ||
} | ||
|
||
export async function disable (params) { | ||
const [addonIdOrName, route, destination] = params.args; | ||
|
||
await enableWaf(addonIdOrName, route, destination); | ||
} | ||
|
||
export async function get (params) { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import colors from 'colors/safe.js'; | ||
|
||
import { Logger } from '../logger.js'; | ||
import { select } from '@inquirer/prompts'; | ||
import { getOtoroshiApiParams, sendToOtoroshi } from './otoroshi.js'; | ||
import { createBiscuitVerifier, createRoute, genBiscuitKeypair, getBiscuitKeypair, getBiscuitKeypairs, getBiscuitKeypairsTemplate, getBiscuitVerifierTemplate, getRouteTemplate } from './otoroshi-instances-api.js'; | ||
|
||
export async function protectRoute (addonIdOrName, pathToProtect, destination) { | ||
const otoroshi = await getOtoroshiApiParams(addonIdOrName); | ||
|
||
const keypairs = await getBiscuitKeypairs(otoroshi).then(sendToOtoroshi); | ||
|
||
if (!keypairs.length) { | ||
throw new Error(`No biscuit keypair found, please generate one first with ${colors.blue('clever biscuits gen-keypair')} command`); | ||
} | ||
|
||
let keypair = keypairs[0].id; | ||
if (keypairs.length > 0) { | ||
keypair = await select({ | ||
type: 'select', | ||
name: 'keypairId', | ||
message: 'Select a keypair to use:', | ||
choices: keypairs.map((keypair) => ({ | ||
name: `${keypair.name} (${keypair.pubKey})`, | ||
value: keypair.id, | ||
})), | ||
}); | ||
} | ||
|
||
const responseTemplate = await getBiscuitVerifierTemplate(otoroshi).then(sendToOtoroshi); | ||
|
||
const verifier = await responseTemplate.json(); | ||
verifier.keypair_ref = keypair; | ||
verifier.config.checks = ['check if time($time), $time <= 2025-03-30T20:00:00Z;']; | ||
verifier.config.policies = ['allow if user("davlgd");']; | ||
|
||
const createdVerifier = await createBiscuitVerifier(otoroshi, verifier).then(sendToOtoroshi); | ||
|
||
const verifierPlugin = { | ||
enabled: true, | ||
debug: false, | ||
plugin: 'cp:otoroshi_plugins.com.cloud.apim.otoroshi.extensions.biscuit.plugins.BiscuitTokenValidator', | ||
config: { | ||
verifier_ref: createdVerifier.id, | ||
extractor_type: 'header', | ||
extractor_name: 'Authorization', | ||
}, | ||
}; | ||
|
||
const [hostname, ...path] = destination.split('/'); | ||
const route = await getRouteTemplate(otoroshi).then(sendToOtoroshi); | ||
route.frontend.domains = [`${otoroshi.routeBaseDomain}${pathToProtect}`]; | ||
route.backend.targets[0].hostname = hostname; | ||
route.backend.root = `/${path.join('/')}`; | ||
route.plugins.push(verifierPlugin); | ||
|
||
await createRoute(otoroshi, route).then(sendToOtoroshi); | ||
|
||
Logger.println(`${colors.green('✔')} Route protection enabled successfully`); | ||
Logger.println(` └─ URL: ${colors.blue(`http://${otoroshi.routeBaseDomain}${pathToProtect}`)}`); | ||
} | ||
|
||
export async function getBiscuitsKeyPairTemplate (addonIdOrName) { | ||
const auth = await getOtoroshiApiParams(addonIdOrName); | ||
return getBiscuitKeypairsTemplate(auth).then(sendToOtoroshi); | ||
} | ||
|
||
export async function genBiscuitsKeypair (addonIdOrName, body) { | ||
const auth = await getOtoroshiApiParams(addonIdOrName); | ||
return genBiscuitKeypair(auth, body).then(sendToOtoroshi); | ||
} | ||
|
||
export async function getBiscuitsKeypair (addonIdOrName, keypairId) { | ||
const auth = await getOtoroshiApiParams(addonIdOrName); | ||
return getBiscuitKeypair(auth, keypairId).then(sendToOtoroshi); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import colors from 'colors/safe.js'; | ||
|
||
import { Logger } from '../logger.js'; | ||
import { getOtoroshiApiParams, sendToOtoroshi } from './otoroshi.js'; | ||
import { createRoute, createWaf, getRouteTemplate, getWafTemplate } from './otoroshi-instances-api.js'; | ||
|
||
export async function enableWaf (addonIdOrName, pathToProtect, destination) { | ||
const otoroshi = await getOtoroshiApiParams(addonIdOrName); | ||
|
||
const responseTemplate = await getWafTemplate(otoroshi).then(sendToOtoroshi); | ||
const waf = await responseTemplate.json(); | ||
waf.name = pathToProtect; | ||
waf.description = `WAF for ${pathToProtect}`; | ||
|
||
const responseWafConfig = await createWaf(otoroshi, waf).then(sendToOtoroshi); | ||
const createdWafConfig = await responseWafConfig.json(); | ||
|
||
const wafPlugin = { | ||
enabled: true, | ||
debug: false, | ||
plugin: 'cp:otoroshi.wasm.proxywasm.NgCorazaWAF', | ||
config: { | ||
ref: createdWafConfig.id, | ||
}, | ||
}; | ||
|
||
const [hostname, ...path] = destination.split('/'); | ||
const responseRoute = await getRouteTemplate(otoroshi).then(sendToOtoroshi); | ||
const route = await responseRoute.json(); | ||
route.frontend.domains = [`${otoroshi.routeBaseDomain}${pathToProtect}`]; | ||
route.backend.targets[0].hostname = hostname; | ||
route.backend.root = `/${path.join('/')}`; | ||
route.plugins.push(wafPlugin); | ||
|
||
await createRoute(otoroshi, route).then(sendToOtoroshi); | ||
|
||
Logger.println(`${colors.green('✔')} WAF enabled successfully`); | ||
Logger.println(` └─ URL: ${colors.blue(`http://${otoroshi.routeBaseDomain}${pathToProtect}`)}`); | ||
} |