#!/usr/bin/env node var wiki_js; wiki_js = (wiki_js || {}); wiki_js.cli = (wiki_js.cli || {}); wiki_js.cli.helpers = (wiki_js.cli.helpers || {}); wiki_js.cli.helpers.string = (wiki_js.cli.helpers.string || {}); (function (exports) { /** */ function coin( template, arguments_ ) { let result = template; Object.entries(arguments_).forEach( ([key, value]) => { result = result.replace(new RegExp("{{" + key + "}}", "g"), value); } ); return result; } exports.coin = coin; }) (wiki_js.cli.helpers.string) var wiki_js; wiki_js = (wiki_js || {}); wiki_js.cli = (wiki_js.cli || {}); wiki_js.cli.helpers = (wiki_js.cli.helpers || {}); wiki_js.cli.helpers.file = (wiki_js.cli.helpers.file || {}); (function (exports) { /** */ function read( path ) { const nm_fs = require("fs"); return ( new Promise( (resolve, reject) => { nm_fs.readFile( path, { }, (err, data) => { if (err) { reject(err); } else { resolve(data.toString()); } } ); } ) ); } exports.read = read; }) (wiki_js.cli.helpers.file) var wiki_js; wiki_js = (wiki_js || {}); wiki_js.cli = (wiki_js.cli || {}); wiki_js.cli.helpers = (wiki_js.cli.helpers || {}); wiki_js.cli.helpers.http = (wiki_js.cli.helpers.http || {}); (function (exports) { /** */ async function call( http_request ) { wiki_js.cli.helpers.log.write( "debug", "http_call_request", http_request ); const fetch_request = new Request( http_request.target, { "method": http_request.method, "headers": http_request.headers, "body": http_request.body, } ); const fetch_response = await fetch(fetch_request); const http_response = { "status_code": fetch_response.status, "headers": fetch_response.headers, "body": await fetch_response.text(), }; wiki_js.cli.helpers.log.write( "debug", "http_call_response", http_response ); return http_response; } exports.call = call; }) (wiki_js.cli.helpers.http) var wiki_js; wiki_js = (wiki_js || {}); wiki_js.cli = (wiki_js.cli || {}); wiki_js.cli.helpers.log = (wiki_js.cli.helpers.log || {}); (function (exports) { /** */ const _level_order = [ "debug", "info", "notice", "warning", "error", ]; /** */ var _threshold = "info"; /** */ function setup( threshold ) { _threshold = threshold; } exports.setup = setup; /** */ function write( level, incident, details ) { if (_level_order.indexOf(level) < _level_order.indexOf(_threshold)) { // do nothing } else { process.stderr.write( wiki_js.cli.helpers.string.coin( "\n<{{datetime}}> [{{level}}] {{incident}}\n{{details}}\n\n", { "datetime": (new Date()).toISOString(), "level": level, "incident": incident, "details": JSON.stringify(details, undefined, "\t"), } ) ); } } exports.write = write; }) (wiki_js.cli.helpers.log); var wiki_js; wiki_js = (wiki_js || {}); wiki_js.cli = (wiki_js.cli || {}); wiki_js.cli.helpers.args = (wiki_js.cli.helpers.args || {}); (function (exports) { /** */ function parse( args_raw ) { let result = { "positional": [], "volatile": {}, }; let state = "free"; let key = null; args_raw.forEach( (arg_raw) => { switch (state) { case "free": { if (arg_raw.startsWith("-")) { key = arg_raw.slice(1); state = "bound"; } else { if (key === null) { result.positional.push(arg_raw); key = null; state = "free"; } else { wiki_js.cli.helpers.log.write( "warning", "arg_discarded", { "arg_raw": arg_raw, } ); key = null; state = "free"; } } break; } case "bound": { if (! (key in result["volatile"])) { result["volatile"][key] = []; } else { // do nothing } result["volatile"][key].push(arg_raw); key = null; state = "free"; } } } ); return result; } exports.parse = parse; }) (wiki_js.cli.helpers.args); var wiki_js; wiki_js = (wiki_js || {}); wiki_js.cli = (wiki_js.cli || {}); wiki_js.cli.conf = (wiki_js.cli.conf || {}); (function (exports) { /** */ var _data = null; /** */ async function load( path ) { let data_raw; if (path === null) { data_raw = {}; } else { const content = await wiki_js.cli.helpers.file.read(path); data_raw = JSON.parse(content); } wiki_js.cli.helpers.log.write( "debug", "conf_raw", data_raw ); _data = { "api": { "url_base": ( data_raw?.api?.url_base ?? "http://localhost:3000" ), }, "login": { "username": ( data_raw?.login?.username ?? "admin" ), "password": ( data_raw?.login?.password ?? "admin" ), }, "log": { "threshold": ( data_raw?.log?.threshold ?? "debug" ), } }; return Promise.resolve(undefined); } exports.load = load; /** */ function set( data ) { _data = data; } exports.set = set; /** */ function get( ) { return _data; } exports.get = get; }) (wiki_js.cli.conf); var wiki_js; wiki_js = (wiki_js || {}); wiki_js.cli = (wiki_js.cli || {}); wiki_js.cli.api = (wiki_js.cli.api || {}); (function (exports) { /** */ async function call_finalize( admin_email, admin_password, site_url, telemetry ) { const http_request = { "target": (wiki_js.cli.conf.get().api.url_base + "/finalize"), "method": "POST", "headers": { "Content-Type": "application/json", }, "body": JSON.stringify( { "adminEmail": admin_email, "adminPassword": admin_password, "adminPasswordConfirm": admin_password, "siteUrl": site_url, "telemetry": telemetry, } ), }; http_response = await wiki_js.cli.helpers.http.call(http_request); const data = JSON.parse(http_response.body); return Promise.resolve(undefined); } exports.call_finalize = call_finalize; /** */ async function call_generic_graphql( graphql_query, options ) { options = Object.assign( { "login_token": null, "variables": {}, }, options ); const http_request = { "target": (wiki_js.cli.conf.get().api.url_base + "/graphql"), "method": "POST", "headers": Object.assign( { "Content-Type": "application/json", }, ( (options.login_token === null) ? {} : {"Cookie": ("jwt=" + options.login_token)} ) ), "body": JSON.stringify( [ { "operationName": null, "variables": options.variables, "extensions": {}, "query": graphql_query, } ] ), }; http_response = await wiki_js.cli.helpers.http.call(http_request); const data = JSON.parse(http_response.body); return Promise.resolve(data[0]["data"]); } /** * executes a local login and returns the JWT */ function call_login_local( ) { wiki_js.cli.helpers.log.write( "info", "api_call_login_local", { } ); return ( call_generic_graphql( "mutation ($username: String!, $password: String!, $strategy: String!) {authentication {login(username: $username, password: $password, strategy: $strategy) {responseResult {succeeded errorCode slug message __typename} jwt mustChangePwd mustProvideTFA mustSetupTFA continuationToken redirect tfaQRImage __typename} __typename}}", { "variables": { "strategy": "local", "username": wiki_js.cli.conf.get().login.username, "password": wiki_js.cli.conf.get().login.password, } } ) .then( (data) => ( data["authentication"]["login"]["responseResult"]["succeeded"] ? Promise.resolve(data["authentication"]["login"]["jwt"]) : Promise.reject(new Error("login failed")) ) ) ); } exports.call_login_local = call_login_local; /** */ function call_email_settings_set( login_token, settings ) { wiki_js.cli.helpers.log.write( "info", "api_call_email_settings_set", { "settings": settings, } ); return ( call_generic_graphql( "mutation ($senderName: String!, $senderEmail: String!, $host: String!, $port: Int!, $name: String!, $secure: Boolean!, $verifySSL: Boolean!, $user: String!, $pass: String!, $useDKIM: Boolean!, $dkimDomainName: String!, $dkimKeySelector: String!, $dkimPrivateKey: String!) {mail {updateConfig(senderName: $senderName, senderEmail: $senderEmail, host: $host, port: $port, name: $name, secure: $secure, verifySSL: $verifySSL, user: $user, pass: $pass, useDKIM: $useDKIM, dkimDomainName: $dkimDomainName, dkimKeySelector: $dkimKeySelector, dkimPrivateKey: $dkimPrivateKey) {responseResult {succeeded errorCode slug message __typename} __typename} __typename}}", { "login_token": login_token, "variables": { "senderName": settings.sender_name, "senderEmail": settings.sender_email_address, "host": settings.smtp_host, "port": settings.smtp_port, "name": settings.name, "secure": settings.secure, "verifySSL": settings.verify_ssl, "user": settings.smtp_username, "pass": settings.smtp_password, "useDKIM": settings.use_dkim, "dkimDomainName": settings.dkim_domain_name, "dkimKeySelector": settings.dkim_key_selector, "dkimPrivateKey": settings.dkim_private_key, } } ) ); } exports.call_email_settings_set = call_email_settings_set; /** */ function call_authentication_strategy_list( login_token ) { wiki_js.cli.helpers.log.write( "info", "api_call_authentication_strategy_list", { } ); return ( call_generic_graphql( "{authentication {activeStrategies {key strategy {key title description useForm logo website __typename} config {key value __typename} order isEnabled displayName selfRegistration domainWhitelist autoEnrollGroups __typename} __typename}}", { "login_token": login_token, } ) .then( (data) => Promise.resolve(data["authentication"]["activeStrategies"]) ) ); } exports.call_authentication_strategy_list = call_authentication_strategy_list; /** */ function call_authentication_strategy_set( login_token, strategies ) { wiki_js.cli.helpers.log.write( "info", "api_call_authentication_strategy_set", { "strategies": strategies, } ); return ( call_generic_graphql( "mutation ($strategies: [AuthenticationStrategyInput]!) {authentication {updateStrategies(strategies: $strategies) {responseResult {succeeded errorCode slug message __typename} __typename} __typename}}", { "login_token": login_token, "variables": { "strategies": strategies, } } ) ); } exports.call_authentication_strategy_set = call_authentication_strategy_set; /** */ function call_theming_set( login_token, dark_mode, toc_position ) { wiki_js.cli.helpers.log.write( "info", "api_call_theming_set", { "dark_mode": dark_mode, "toc_position": toc_position, } ); return ( call_generic_graphql( "mutation ($theme: String!, $iconset: String!, $darkMode: Boolean!, $tocPosition: String, $injectCSS: String, $injectHead: String, $injectBody: String) {theming {setConfig(theme: $theme, iconset: $iconset, darkMode: $darkMode, tocPosition: $tocPosition, injectCSS: $injectCSS, injectHead: $injectHead, injectBody: $injectBody) {responseResult {succeeded errorCode slug message __typename} __typename} __typename}}", { "login_token": login_token, "variables": { "theme": "default", "iconset": "mdi", "darkMode": dark_mode, "tocPosition": "left", "injectCSS": "", "injectHead": "", "injectBody": "" } } ) ); } exports.call_theming_set = call_theming_set; }) (wiki_js.cli.api); var wiki_js; wiki_js = (wiki_js || {}); wiki_js.cli = (wiki_js.cli || {}); wiki_js.cli.logic = (wiki_js.cli.logic || {}); (function (exports) { /** */ async function initialize( admin_email_address, admin_password, options ) { options = Object.assign( { "site_url": "http://localhost:3000", "allow_telemetry": false, }, options ); const result = await wiki_js.cli.api.call_finalize( admin_email_address, admin_password, options.site_url, options.allow_telemetry ); return Promise.resolve(undefined); } exports.initialize = initialize; /** */ async function email_settings_set( smtp_host, smtp_port, smtp_username, smtp_password, sender_name, sender_email_address, options ) { options = Object.assign( { }, options ); const login_token = await wiki_js.cli.api.call_login_local( ); const result = await wiki_js.cli.api.call_email_settings_set( login_token, { "sender_name": sender_name, "sender_email_address": sender_email_address, "smtp_host": smtp_host, "smtp_port": smtp_port, "secure": true, "verify_ssl": true, "smtp_username": smtp_username, "smtp_password": smtp_password, "name": "", "use_dkim": false, "dkim_domain_name": "", "dkim_key_selector": "", "dkim_private_key": "", } ); return Promise.resolve(undefined); } exports.email_settings_set = email_settings_set; /** */ async function authentication_strategy_list( ) { const login_token = await wiki_js.cli.api.call_login_local( ); const result = await wiki_js.cli.api.call_authentication_strategy_list( login_token ); return Promise.resolve(result); } exports.authentication_strategy_list = authentication_strategy_list; /** */ async function authentication_strategy_add( strategy ) { const login_token = await wiki_js.cli.api.call_login_local( ); const current = await wiki_js.cli.api.call_authentication_strategy_list( login_token ); const result = await wiki_js.cli.api.call_authentication_strategy_set( login_token, ( ( current .map( (entry) => ({ "key": entry["key"], "strategyKey": entry["strategy"]["key"], "displayName": entry["displayName"], "order": entry["order"], "isEnabled": entry["isEnabled"], "config": ( entry["config"] .map( (item) => ({ "key": item["key"], "value": JSON.stringify({"v": JSON.parse(item["value"])["value"]}), }) ) ), "selfRegistration": entry["selfRegistration"], "domainWhitelist": entry["domainWhitelist"], "autoEnrollGroups": entry["autoEnrollGroups"], }) ) ) .concat( [ { "key": strategy.key, "strategyKey": "oauth2", "displayName": strategy.name, "order": ( ( current .map(x => x["order"]) .reduce((x,y) => (((x === null) || (x < y)) ? y : x), null) ) + 1 ), "isEnabled": true, "config": [ { "key": "clientId", "value": JSON.stringify({"v": strategy.client_id}), }, { "key": "clientSecret", "value": JSON.stringify({"v": strategy.client_secret}), }, { "key": "authorizationURL", "value": JSON.stringify({"v": strategy.authorization_url}), }, { "key": "tokenURL", "value": JSON.stringify({"v": strategy.token_url}), }, { "key": "userInfoURL", "value": JSON.stringify({"v": strategy.user_info_url}), }, { "key": "userIdClaim", "value": JSON.stringify({"v": "id"}), }, { "key": "displayNameClaim", "value": JSON.stringify({"v": "name"}), }, { "key": "emailClaim", "value": JSON.stringify({"v": "email"}), }, { "key": "mapGroups", "value": JSON.stringify({"v": false}), }, { "key": "groupsClaim", "value": JSON.stringify({"v": "groups"}), }, { "key": "logoutURL", "value": JSON.stringify({"v": ""}), }, { "key": "scope", "value": JSON.stringify({"v": "openid profile email"}), }, { "key": "useQueryStringForAccessToken", "value": JSON.stringify({"v": false}), }, { "key": "enableCSRFProtection", "value": JSON.stringify({"v": true}), } ], "selfRegistration": true, "domainWhitelist": [], "autoEnrollGroups": [] }, ] ) ) ); return Promise.resolve(undefined); } exports.authentication_strategy_add = authentication_strategy_add; /** */ async function theming_set( options = {} ) { options = Object.assign( { "dark_mode": false, "toc_position": "left", }, options ); const login_token = await wiki_js.cli.api.call_login_local( ); const result = await wiki_js.cli.api.call_theming_set( login_token, options.dark_mode, options.toc_position ); return Promise.resolve(result); } exports.theming_set = theming_set; }) (wiki_js.cli.logic); var wiki_js; wiki_js = (wiki_js || {}); wiki_js.cli = (wiki_js.cli || {}); (function (exports) { /** */ async function main( args_raw ) { // args const args = wiki_js.cli.helpers.args.parse(args_raw); const override_url_base = ( ( ("b" in args.volatile) && (args.volatile["b"].length >= 0) ) ? args.volatile["b"][0] : null ); const override_username = ( ( ("u" in args.volatile) && (args.volatile["u"].length >= 0) ) ? args.volatile["u"][0] : null ); const override_password = ( ( ("p" in args.volatile) && (args.volatile["p"].length >= 0) ) ? args.volatile["p"][0] : null ); // conf const conf_path = ( ( ("c" in args.volatile) && (args.volatile["c"].length >= 0) ) ? args.volatile["c"][0] : null ); await wiki_js.cli.conf.load(conf_path); let conf_override = wiki_js.cli.conf.get(); ((override_url_base !== null) && (conf_override.api.url_base = override_url_base)); ((override_username !== null) && (conf_override.login.username = override_username)); ((override_password !== null) && (conf_override.login.password = override_password)); wiki_js.cli.conf.set(conf_override); wiki_js.cli.helpers.log.write( "debug", "conf", wiki_js.cli.conf.get() ); // init wiki_js.cli.helpers.log.setup(wiki_js.cli.conf.get().log.threshold); // exec if (args.positional.length < 1) { return Promise.reject("SYNTAX: [node] cli.js [-c ] [-b ] [-u ] [-p ] [ [ […]]]\n\n\t = init | email-settings-set | auth-strat-list | auth-strat-add-oauth2"); } else { const action = args.positional[0]; switch (action) { default: { return Promise.reject("invalid action: " + action); break; } case "init": { if (args.positional.length <= 2) { return Promise.reject("SYNTAX: … init [ []]"); } else { await wiki_js.cli.logic.initialize( args.positional[1], args.positional[2], { "site_url": ( (args.positional.length >= 4) ? args.positional[3] : undefined ), "allow_telemtry": ( (args.positional.length >= 5) ? (args.positional[4] === "1") : undefined ), } ); return Promise.resolve(undefined); } break; } case "email-settings-set": { if (args.positional.length <= 6) { return Promise.reject("SYNTAX: … email-settings-set "); } else { await wiki_js.cli.logic.email_settings_set( args.positional[1], parseInt(args.positional[2]), args.positional[3], args.positional[4], args.positional[5], args.positional[6], { } ); return Promise.resolve(undefined); } } case "auth-strat-list": { const result = await wiki_js.cli.logic.authentication_strategy_list(); process.stdout.write( JSON.stringify( result, undefined, "\t" ) + "\n" ); return Promise.resolve(undefined); break; } case "auth-strat-add-oauth2": { if (args.positional.length <= 7) { return Promise.reject("SYNTAX: … auth-strat-add-oauth2 "); } else { await wiki_js.cli.logic.authentication_strategy_add( { "key": args.positional[1], "name": args.positional[2], "client_id": args.positional[3], "client_secret": args.positional[4], "authorization_url": args.positional[5], "token_url": args.positional[6], "user_info_url": args.positional[7], } ); return Promise.resolve(undefined); } break; } case "theming-set": { if (args.positional.length <= 2) { return Promise.reject("SYNTAX: … theming-set []"); } else { await wiki_js.cli.logic.theming_set( { "dark_mode": (args.positional[1] === "1"), "toc_position": args.positional[2], } ); return Promise.resolve(undefined); } break; } } } } exports.main = main; }) (wiki_js.cli); ( wiki_js.cli.main(process.argv.slice(2)) .then( () => { } ) .catch( (reason) => { process.stderr.write("-- " + String(reason) + "\n"); } ) );