Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@teqed/interact-ibmi

Package Overview
Dependencies
Maintainers
1
Versions
52
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@teqed/interact-ibmi - npm Package Compare versions

Comparing version 1.0.39 to 1.0.40

build/menu/main/help-user/change/change-password.js

3

build/main.js
#! /usr/bin/env node
/* eslint-disable node/shebang */
import findUsers from './util/find-users.js';
import login from './menu/login/login.js';
import mainMenu from './menu/main/menu-main.js';
// import findUsers from './util/find-users.js';
import findUsers from './util/find-users.js';
// import { welcome } from './util.js';

@@ -7,0 +8,0 @@ process.title = `interact-ibmi`;

@@ -1,6 +0,2 @@

/* This is the menu system for the application.
It shows the user options and lets them choose what they want to do.
They can send commands to the IBMi or run SQL inputCommands over ODBC connections. */
import ora from 'ora';
import { sleep } from '../util.js';
// eslint-disable-next-line import/no-mutable-exports

@@ -10,7 +6,7 @@ export let exitMenuMain = false;

const spinner = ora(`Exiting...`).start();
await sleep();
spinner.fail(`Exited cleanly.`);
exitMenuMain = true;
/* Throw an error to exit the program */
spinner.succeed(`Exited cleanly.`);
return new Error(`Exited cleanly.`);
}
// TODO - https://github.com/jtlapp/node-cleanup

@@ -1,6 +0,7 @@

import chalk from 'chalk';
import confirm from '@inquirer/confirm';
import { createPrompt, useState, useKeypress, isEnterKey, usePrefix, isSpaceKey, } from '@inquirer/core';
import input from '@inquirer/input';
import rawlist from '@inquirer/rawlist';
import select from '@inquirer/select';
import { createPrompt, useState, useKeypress, isEnterKey, usePrefix, isSpaceKey, } from '@inquirer/core';
import chalk from 'chalk';
// The genericGetCommand function is used to get a command from the user.

@@ -11,3 +12,2 @@ // It can be used to run queries or system commands, or to get input from the user.

export const genericGetCommand = async (prompt) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
const command = await input({ default: prompt.default, message: prompt.message }, { clearPromptOnDone: prompt.clearPromptOnDone ?? true });

@@ -19,4 +19,3 @@ return command;

// genericListMenu is used to display a list of options to the user.
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
const menu = (await rawlist({
const menu = await rawlist({
// Add a choice for every option in the array prompt.choices.

@@ -30,3 +29,3 @@ choices: prompt.choices.map(choice => {

message: prompt.message,
}, { clearPromptOnDone: prompt.clearPromptOnDone ?? true }));
}, { clearPromptOnDone: prompt.clearPromptOnDone ?? true });
return menu;

@@ -59,4 +58,3 @@ };

console.clear();
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
const menu = (await rawlist({
const menu = await rawlist({
choices: prompt.choices.map(choice => {

@@ -69,3 +67,3 @@ return {

message: prompt.message,
}, { clearPromptOnDone: prompt.clearPromptOnDone ?? true }));
}, { clearPromptOnDone: prompt.clearPromptOnDone ?? true });
return menu;

@@ -87,3 +85,2 @@ };

export const genericPasswordMenu = async (config) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
return input({

@@ -112,3 +109,3 @@ default: undefined,

if (isEnterKey(key)) {
const answer = value ? /^y(es)?/i.test(value) : config.default !== false;
const answer = value ? /^y(es)?/iu.test(value) : config.default !== false;
setValue(answer ? `yes` : `no`);

@@ -128,3 +125,3 @@ setStatus(`done`);

if (isSpaceKey(key)) {
const answer = value ? /^y(es)?/i.test(value) : config.default !== false;
const answer = value ? /^y(es)?/iu.test(value) : config.default !== false;
setValue(answer ? `yes` : `no`);

@@ -179,1 +176,7 @@ setStatus(`done`);

};
export const genericConfirmPrompt = async (config) => {
return await confirm({
default: config._default ?? false,
message: config.message,
}, { clearPromptOnDone: config.clearPromptOnDone ?? true });
};
/* This is the login module.
It asks for the user's name and password, which is used for logging in to the IBMi AS400. */
import ora from 'ora';
import { odbcLogin } from '../../util/odbc/odbc-util.js';
import sequelizeLogin from '../../util/sequelize/connection.js';
import { genericGetCommand, genericPasswordMenu } from '../generic.js';

@@ -16,3 +18,2 @@ export default async () => {

});
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const loginPw = await genericPasswordMenu({

@@ -23,3 +24,25 @@ clearPromptOnDone: false,

});
return odbcLogin(loginId, loginPw, loginSys);
const odbcLoginThing = odbcLogin(loginId, loginPw, loginSys);
const sequelizeLoginThing = sequelizeLogin(loginId, loginPw, loginSys);
let fail;
const spinner = ora(`Logging in to ODBC...`).start();
if (await odbcLoginThing) {
spinner.succeed(`Logged in to ODBC!`);
}
else {
spinner.fail(`Login failed!`);
fail = true;
}
const spinner2 = ora(`Logging in to Sequelize...`).start();
if (await sequelizeLoginThing) {
spinner2.succeed(`Logged in to Sequelize!`);
}
else {
spinner2.fail(`Login failed!`);
fail = true;
}
if (fail) {
throw new Error(`Login failed!`);
}
return { loginId, loginPw, loginSys };
};
import chalk from 'chalk';
import ora from 'ora';
import printJobLog from '../../util/odbc/print-job-log.js';
import { parseODBCErrorMessage } from '../../util/qcmdexc/qcmdexc-util.js';
import QCMDEXC from '../../util/qcmdexc/qcmdexc.js';
import executeCommand from '../../util/qcmdexc/execute-command.js';
import { genericGetCommand, genericPressEnterPrompt } from '../generic.js';

@@ -11,15 +8,16 @@ export default async function () {

});
const spinner = ora(`Executing command ${chalk.green(inputCommand)}`).start();
try {
const rtnCommand = await QCMDEXC(inputCommand);
/* Find the output from rtnCommand */
spinner.succeed(`Command executed!`);
console.log(rtnCommand);
const commandExecute = await executeCommand(inputCommand, {
pauseOnError: false,
throwOnError: false,
});
// Console log commandExecute if it's not void.
if (commandExecute) {
console.log(commandExecute);
}
catch (error) {
const parsedError = await parseODBCErrorMessage(error);
spinner.fail(`${chalk.red(parsedError.messageIdentifier)} - ${chalk.yellow(parsedError.messageText)}`);
await printJobLog();
else {
console.log(`
${chalk.blueBright(`Command failed. See job log for details.`)}
`);
}
return genericPressEnterPrompt();
}
import ora from 'ora';
import { sleep } from '../../../util.js';
import { foundUsers } from '../../../util/find-users.js';
import getRows from '../../../util/odbc/get-rows-odbc.js';
import { generatedSelectMenu, genericPressEnterPrompt } from '../../generic.js';
import { sleep } from '../../../util.js';
import getRows from '../../../util/odbc/get-rows-odbc.js';
const fullUserInfo = async (user) => {

@@ -17,2 +17,3 @@ const query = `SELECT * FROM QSYS2.USER_INFO WHERE AUTHORIZATION_NAME = '${user}'`;

const spinner = ora(`Finding users...`).start();
// eslint-disable-next-line no-unmodified-loop-condition
while (foundUsers === undefined) {

@@ -19,0 +20,0 @@ // eslint-disable-next-line no-await-in-loop

import chalk from 'chalk';
import { genericSelectMenu } from '../../generic.js';
import copyuser from './copyuser.js';
import changePasswordMenu from './change/change-password.js';
import copyuser from './copy/copyuser.js';
import deleteUserMenu from './delete/delete-user.js';
import displayUserMenu from './display-user.js';
import reenableUserMenu from './reenableuser.js';
import reenableNetserverUser from './reenable-netserver-user.js';
import reenableUserMenu from './reenable-user.js';
// Create an array of strings containing menu choices.

@@ -12,6 +15,6 @@ export default async function () {

`2. Copy User`,
`3. (WIP) Delete User`,
`4. (WIP) Change User Password`,
`3. Delete User`,
`4. Change User Password`,
`5. Reenable User`,
`6. (WIP) Unlock NetDrive User`,
`6. Unlock Netserver User`,
`7. Previous Menu`, // 6 - exitMenu

@@ -36,7 +39,7 @@ ];

case menuChoice[2]: {
// return await deleteUserMenu();
return await deleteUserMenu();
break;
}
case menuChoice[3]: {
// return await changePasswordMenu();
return await changePasswordMenu();
break;

@@ -49,3 +52,3 @@ }

case menuChoice[5]: {
// return await unlockUserMenu();
await reenableNetserverUser();
break;

@@ -52,0 +55,0 @@ }

import ora from 'ora';
import diagnoseUsers from '../../../util/diagnose-users.js';
import { foundUsers } from '../../../util/sequelize/find-users.js';
import { generatedSelectMenu } from '../../generic.js';
import diagnoseUsers from '../../../util/diagnose-users.js';
import { foundUsers } from '../../../util/find-users.js';
export default async function () {

@@ -6,0 +6,0 @@ const spinner = ora(`Checking...`).start();

import chalk from 'chalk';
import exitMenu, { exitMenuMain } from '../exit.js';
import { genericSelectMenu, genericPressEnterPrompt } from '../generic.js';
import exitMenu, { exitMenuMain } from '../exit.js';
import odbcMenu from './odbc.js';
import cmdMenu from './cmd.js';
import helpUsersMenu from './help-user/help-user.js';
import testFunction from './test-function.js';
import odbcMenu from './odbc.js';
import testFunction from './test/test-function.js';
export default async () => {

@@ -16,2 +16,3 @@ const menuChoice = [

];
// eslint-disable-next-line no-unmodified-loop-condition
while (!exitMenuMain)

@@ -33,2 +34,3 @@ /* Create an array of strings containing menu choices. */

await odbcMenu();
await genericPressEnterPrompt();
return 0;

@@ -40,4 +42,5 @@ }

case menuChoice[3]: {
console.log(await testFunction());
return genericPressEnterPrompt();
await testFunction();
await genericPressEnterPrompt();
return 0;
}

@@ -44,0 +47,0 @@ default: {

/* This contains utility functions for the application. */
import chalkAnimation from 'chalk-animation';
// Sleep for X milliseconds, or a default of a half second.
// eslint-disable-next-line func-style
export async function sleep(milliseconds = 500) {

@@ -17,2 +18,3 @@ return new Promise(resolve =>

};
// eslint-disable-next-line func-style
export function qualifyObject(LibraryAndObject) {

@@ -50,1 +52,25 @@ // TODO: Test the special object parameters.

};
/* eslint-disable unicorn/no-null */
export const stringToBoolean = (string) => {
switch (string.toLowerCase().trim()) {
case `true`:
case `yes`:
case `y`:
case `1`:
return true;
case `false`:
case `fals`:
case `fal`:
case `fa`:
case `f`:
case `no`:
case `n`:
case `0`:
case null:
case undefined:
return false;
default:
return Boolean(string);
}
};
/* eslint-enable unicorn/no-null */

@@ -12,3 +12,4 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */

MESSAGE_TEXT, \
MESSAGE_SECOND_LEVEL_TEXT \
MESSAGE_SECOND_LEVEL_TEXT, \
SEVERITY \
from table(qsys2.joblog_info('${jobName}'))`));

@@ -15,0 +16,0 @@ // For each element in the array, push it to the jobMessages2 array.

@@ -12,3 +12,2 @@ import chalk from 'chalk';

const object = {};
// eslint-disable-next-line no-restricted-syntax
for (const column of query.columns) {

@@ -15,0 +14,0 @@ object[column.name] = row[column.name];

@@ -5,3 +5,3 @@ import chalk from 'chalk';

export default async function () {
const jobName = await getJobInfo();
const jobName = await getJobInfo(); // TODO - Get the job name at initialization.
const jobMessages = await getJobMessages(jobName);

@@ -17,22 +17,55 @@ // Log the job messages to the console.

jobMessages.forEach(message => {
const severityMessageString = `Sev:${message.SEVERITY}`;
let coloredSeverity = chalk.whiteBright(severityMessageString);
switch (message.SEVERITY) {
case 0:
coloredSeverity = chalk.whiteBright(`Sev: 0`);
break;
case 10:
coloredSeverity = chalk.green(severityMessageString);
break;
case 20:
coloredSeverity = chalk.yellow(severityMessageString);
break;
case 30:
coloredSeverity = chalk.red(severityMessageString);
break;
case 40:
coloredSeverity = chalk.red.bgBlack(severityMessageString);
break;
default:
coloredSeverity = chalk.whiteBright(severityMessageString);
break;
}
const trimmedMessageTimestamp = message.MESSAGE_TIMESTAMP.slice(0, Math.max(0, message.MESSAGE_TIMESTAMP.indexOf(`.`)));
// eslint-disable-next-line max-len
const messageString = `${coloredSeverity} - ${trimmedMessageTimestamp} - ${message.MESSAGE_ID} - ${message.MESSAGE_TEXT}`;
switch (message.MESSAGE_TYPE) {
case `ESCAPE`:
console.log(chalk.red(messageString));
break;
case `NOTIFY`:
console.log(chalk.red(`${message.MESSAGE_TIMESTAMP} - ${message.MESSAGE_ID} - ${message.MESSAGE_TEXT}`));
console.log(chalk.redBright(messageString));
break;
case `INQUIRY`:
console.log(chalk.yellowBright(messageString));
break;
case `REQUEST`:
console.log(chalk.yellow(`${message.MESSAGE_TIMESTAMP} - ${message.MESSAGE_ID} - ${message.MESSAGE_TEXT}`));
console.log(chalk.yellow(messageString));
break;
case `COMPLETION`:
console.log(chalk.greenBright(messageString));
break;
case `REPLY`:
console.log(chalk.green(`${message.MESSAGE_TIMESTAMP} - ${message.MESSAGE_ID} - ${message.MESSAGE_TEXT}`));
console.log(chalk.green(messageString));
break;
case `INFORMATIONAL`:
console.log(chalk.blueBright(messageString));
break;
case `SCOPE`:
case `SENDER`:
console.log(chalk.white(`${message.MESSAGE_TIMESTAMP} - ${message.MESSAGE_ID} - ${message.MESSAGE_TEXT}`));
console.log(chalk.grey(messageString));
break;
default:
console.log(chalk.white(`${message.MESSAGE_TIMESTAMP} - ${message.MESSAGE_ID} - ${message.MESSAGE_TEXT}`));
console.log(chalk.white(messageString));
break;

@@ -39,0 +72,0 @@ }

@@ -1,17 +0,40 @@

import { queryOdbc } from './odbc-util.js';
export const updateOdbc = async () => {
const query = await queryOdbc(`SELECT * FROM TEQ1.TQ002AP`);
const v1 = `Carol`;
const v2 = query[0][query.columns[1].name];
const v3 = query[0][query.columns[2].name];
const update = await queryOdbc(`INSERT INTO TEQ1.TQ002AP VALUES('${v1}', '${v2}', '${v3}')`);
import { genericGetCommand } from '../../menu/generic.js';
import { stringToBoolean } from '../../util.js';
import { sequelize } from '../sequelize/connection.js';
export default async (table) => {
// Use sequelize to insert a record into table
// Now find the name of each column in the table and store it in an array
const attributes = sequelize.models[table].getAttributes();
const columns = Object.keys(attributes);
// Now prompt the user to enter a value for each column using the genericGetCommand() function
// Then store the values in an array
const values = [];
const columnNames = [];
for (const column of columns) {
// Push current column name to columnNames array
columnNames.push(column);
// eslint-disable-next-line no-await-in-loop
const value = await genericGetCommand({
clearPromptOnDone: false,
message: `Enter a value for ${column}`,
});
// Push value to array
values.push(value);
// await genericGetCommand(`Enter a value for ${column}`);
}
const v1 = values[0];
const v2 = values[1];
const v3 = stringToBoolean(values[2]);
const c1 = columnNames[0];
const c2 = columnNames[1];
const c3 = columnNames[2];
// Now insert a new record from the results.
const update = await sequelize.models[table].create({
[c1]: v1,
[c2]: v2,
[c3]: v3,
});
console.log(update);
const query = await sequelize.models[table].findAll({});
console.log(query);
};
export const updateOdbc2 = async () => {
const query = await queryOdbc(`SELECT * FROM TEQ1.TQ002AP`);
const v1 = `Carol`;
const v2 = query[0][query.columns[1].name];
const v3 = query[0][query.columns[2].name];
const update = await queryOdbc(`INSERT INTO TEQ1.TQ002AP VALUES('${v1}', '${v2}', '${v3}')`);
console.log(update);
};
import chalk from 'chalk';
export function qualifyObject(QualifiedObject) {
export const qualifyObject = (QualifiedObject) => {
// TODO: Test the special object parameters.

@@ -19,7 +19,7 @@ if (QualifiedObject.object === `*SAME` ||

return `${innerLibrary}/${QualifiedObject.object}`;
}
};
/* Parse the input into an object with two properties: 'errorIdentifier' and 'messageText'. */
/* Remove the prefix '[IBM][System i Access ODBC Driver][DB2 for i5/OS]' from the error message. */
/* Separate the error number from the error message where the first space hyphen space is. */
export async function parseErrorMessage(error) {
export const parseErrorMessage = async (error) => {
// https://www.ibm.com/docs/en/i/7.2?topic=odbc-i-access-error-messages

@@ -29,8 +29,8 @@ // [vendor][ODBC-component][data-source] error-message

/* Remove the prefix '[IBM][System i Access ODBC Driver][DB2 for i5/OS]' from the error message. */
message = message.replace(/\[IBM]\[System i Access ODBC Driver]\[DB2 for i5\/OS]/, ``);
message = message.replace(/^\[IBM\]\[System i Access ODBC Driver\]\[DB2 for i5\/OS\] /u, ``);
const errorIdentifier = message.split(` - `)[0];
const messageText = message.split(` - `)[1];
return { errorIdentifier, messageText };
}
export async function parseODBCErrorMessage(error) {
};
export const parseODBCErrorMessage = async (error) => {
/* https://www.ibm.com/docs/en/i/7.2?topic=odbc-i-access-error-messages

@@ -97,7 +97,7 @@ Error messages have the following format:

/* If null, then set to an empty string. */
const vendor = /\[.*?]/.exec(message)?.[0] ?? ``;
const vendor = /\[.*?\]/u.exec(message)?.[0] ?? ``;
message = message.replace(vendor, ``);
const ODBCComponent = /\[.*?]/.exec(message)?.[0] ?? ``;
const ODBCComponent = /\[.*?\]/u.exec(message)?.[0] ?? ``;
message = message.replace(ODBCComponent, ``);
const dataSource = /\[.*?]/.exec(message)?.[0] ?? ``;
const dataSource = /\[.*?\]/u.exec(message)?.[0] ?? ``;
message = message.replace(dataSource, ``);

@@ -115,3 +115,3 @@ // Remove any leading or trailing whitespace.

let messageIdentifier = ``;
let messageText = ``;
let messageText = message;
const dashIndex = message.indexOf(` - `);

@@ -122,5 +122,2 @@ if (dashIndex !== -1) {

}
else {
messageText = message;
}
// Remove any leading or trailing whitespace.

@@ -142,4 +139,4 @@ messageIdentifier = messageIdentifier.trim();

};
}
export async function printODBCError(error) {
};
export const printODBCError = async (error) => {
const { errorMessage, messageIdentifier, messageText } = await parseODBCErrorMessage(error);

@@ -153,2 +150,2 @@ // Log the message identifier and the message text.

console.log(chalk.yellow(`Message . . . . : ${messageText}`));
}
};

@@ -9,6 +9,8 @@ {

"@inquirer/select": "^0.0.27-alpha.0",
"@sequelize/core": "^7.0.0-alpha.18",
"chalk": "^5.0.1",
"chalk-animation": "^2.0.3",
"odbc": "^2.4.4",
"odbc": "^2.4.6",
"ora": "^6.1.2",
"reflect-metadata": "^0.1.13",
"type-fest": "^3.0.0"

@@ -18,3 +20,4 @@ },

"devDependencies": {
"@rollup/plugin-node-resolve": "^14.1.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"@teqed/sequelize-auto": "^0.9.2",
"@tsconfig/node16": "^1.0.3",

@@ -25,8 +28,9 @@ "@types/chai": "^4.3.3",

"@types/mocha": "^10.0.0",
"@types/node": "^18.7.16",
"@types/node": "^18.8.2",
"@types/ora": "^3.2.0",
"@typescript-eslint/eslint-plugin": "^5.36.2",
"@typescript-eslint/parser": "^5.36.2",
"@vitest/coverage-c8": "^0.23.1",
"@vitest/ui": "^0.23.1",
"@types/validator": "^13.7.7",
"@typescript-eslint/eslint-plugin": "^5.39.0",
"@typescript-eslint/parser": "^5.39.0",
"@vitest/coverage-c8": "^0.24.0",
"@vitest/ui": "^0.24.0",
"airbnb": "^0.0.2",

@@ -48,3 +52,3 @@ "aws-sdk": "^2.1212.0",

"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-unicorn": "^43.0.2",
"eslint-plugin-unicorn": "^44.0.2",
"mocha": "^10.0.0",

@@ -56,2 +60,4 @@ "mocha-reporter-badge": "^0.1.0",

"rollup-plugin-visualizer": "^5.8.1",
"sequelize-cli": "^6.5.1",
"sequelize-typescript": "^2.1.3",
"ts-node": "^10.9.1",

@@ -63,4 +69,4 @@ "tslib": "^2.4.0",

"vite-plugin-node": "^1.0.0",
"vite-plugin-progress": "^0.0.4",
"vitest": "^0.23.1",
"vite-plugin-progress": "^0.0.5",
"vitest": "^0.24.0",
"xo": "^0.52.3"

@@ -92,3 +98,3 @@ },

"type": "module",
"version": "1.0.39",
"version": "1.0.40",
"engines": {

@@ -95,0 +101,0 @@ "node": ">=16.0.0"

@@ -10,3 +10,4 @@ <h1 align="center">interact-ibmi</h1>

<p align="center">
<img src="https://user-images.githubusercontent.com/5181964/189458380-25f7f4fc-30e0-47ee-9abb-90dae5ecc957.png" alt="prototype image of interact-ibmi showing some test output">
<img src="https://user-images.githubusercontent.com/5181964/196768386-1b064261-37e7-48a5-ad75-ed9f34a9fb27.png" alt="prototype image of interact-ibmi showing some the login menu">
<img src="https://user-images.githubusercontent.com/5181964/196768413-8038b624-92c0-48ba-8ccc-9c727df3f511.png" alt="prototype image of interact-ibmi showing the main menu">
</p><br><br>

@@ -31,7 +32,5 @@ This is a work-in-progress with the goals of being able to view file records using ODBC, insert new records, and delete selected records, as well as perform some system commands.

* [:heavy_check_mark:] Place new system user on authorization lists and create directory entry
* [:heavy_check_mark:] Show system / user diagnostics upon login
* [❌] Make a new To-do list with the next stretch of goals!
<p align="center">
<img src="https://user-images.githubusercontent.com/5181964/189445594-afe69bba-bcde-4d02-92e9-3fd0aaf70b10.png" alt="prototype image of interact-ibmi showing some user diagnostics">
<img src="https://user-images.githubusercontent.com/5181964/196768438-acba4a63-b754-4bab-a217-af7649244d6c.png" alt="prototype image of interact-ibmi showing some user diagnostics">
<br>

@@ -38,0 +37,0 @@ <sup><small><i>Some basic user diagnostics already done!</i></small></sup>

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc