Socket
Socket
Sign inDemoInstall

ldap-schema-ts-generator

Package Overview
Dependencies
Maintainers
1
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ldap-schema-ts-generator - npm Package Compare versions

Comparing version 0.1.0 to 0.9.9

dist/helpers/generate-class-interface.d.ts

53

dist/app.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const dotenv_1 = require("dotenv");
dotenv_1.config();
const fast_node_logger_1 = require("fast-node-logger");
const schema_1 = require("./services/schema");
const map_class_attributes_1 = require("./helpers/map-class-attributes");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const generateText_1 = require("./helpers/generateText");
const prettier_1 = __importDefault(require("prettier"));
dotenv_1.config();
/**
* 1- get list of objectClass=classSchema
* 2 get list of objectClass=attributeSchema
* 3-1 look at mustContain, systemMustContain, mayContain, and systemMayContain
* 3-2 map attributes with class object
*/
const schemaDn = "CN=Schema,CN=Configuration,DC=ki,DC=local";
const index_1 = require("./index");
async function main() {
var _a, _b, _c;
const logger = await fast_node_logger_1.createLogger({ level: "trace" });
const objectAttributes = await schema_1.getSchemaAttributes({ schemaDn, logger });
const objectClasses = await schema_1.getSchemaClasses({ schemaDn, logger });
const classWithAttributes = map_class_attributes_1.mapClassAttributes({
attributes: objectAttributes,
classObj: objectClasses[0],
});
/** now we have everything we need
* it's time to generate typescript types:
* 1- create handlebar template
* 2- generate type for each attribute
* 3- generate type for each class
* 4- maybe create a class for class object and pre-define CRUD operation like ORM
*/
const rawOutput = generateText_1.generate({ data: classWithAttributes });
/** run prettier at output before write to file */
const output = prettier_1.default.format(rawOutput, { parser: "typescript" });
/** write to file.
* over write if exist
*/
fs_1.default.writeFileSync(path_1.default.join(process.cwd(), "generated", "out.ts"), output, {
encoding: "utf8",
flag: "w",
});
const schemaDn = "CN=Schema,CN=Configuration,DC=ki,DC=local";
const options = {
user: (_a = process.env.AD_USER) !== null && _a !== void 0 ? _a : "",
pass: (_b = process.env.AD_Pass) !== null && _b !== void 0 ? _b : "",
ldapServerUrl: (_c = process.env.AD_URI) !== null && _c !== void 0 ? _c : "",
logger,
};
const objectAttributes = await index_1.getSchemaAttributes({ schemaDn, options });
const objectClasses = await index_1.getSchemaClasses({ schemaDn, options });
await index_1.generateInterfaceFiles({ objectAttributes, objectClasses });
}

@@ -48,0 +21,0 @@ main().catch((err) => {

import { SchemaClassWithAttributes } from "./map-class-attributes";
interface GenerateFnInput {
interface GenerateClassInterfaceFnInput {
data: SchemaClassWithAttributes;
}
export declare function generate({ data }: GenerateFnInput): string;
export declare function generateClassInterface({ data, }: GenerateClassInterfaceFnInput): string;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const type_map_1 = require("./type-map");
function arrayToLines(data) {
if (!data) {
throw new Error("data input required");
}
return data.map((el) => `${el}\n`).join("");
}
function generate({ data }) {
const pascal_case_1 = require("pascal-case");
const utils_1 = require("./utils");
function generateClassInterface({ data, }) {
const result = `
/** object class ${data.ldapName}
* child of class ${data.parentClass}
*/
interface ${data.className} {
${arrayToLines(data.attributes &&
/** - object class: ${data.ldapName}
* - child of class: ${data.parentClass}
* - dn: ${data.originalClassFields.dn}
*/
interface ${pascal_case_1.pascalCase(data.className)} {
${utils_1.arrayToLines(data.attributes &&
data.attributes.map((el) => {
return `"${el.lDAPDisplayName}" ${el.isRequired ? "" : "?"}: ${type_map_1.typeMapper(el.attributeSyntax)} ${el.isSingleValued ? "" : "[]"};`;
return `
/** - attributeSyntax: ${el.attributeSyntax}
* - attributeID: ${el.attributeID}
* - adminDisplayName: ${el.adminDisplayName}
* - adminDescription: ${el.adminDescription}
* - dn: ${el.dn}
*/
${el.systemOnly ? "readonly" : ""} "${el.lDAPDisplayName}" ${el.isRequired ? "" : "?"}: ${type_map_1.typeMapper(el.attributeSyntax)} ${el.isSingleValued ? "" : "[]"};`;
}))}

@@ -24,3 +28,3 @@ }

}
exports.generate = generate;
exports.generateClassInterface = generateClassInterface;
//# sourceMappingURL=generateText.js.map

@@ -1,25 +0,31 @@

import type { SchemaClass, SchemaAttributes } from "../services/schema";
import type { SchemaClass, SchemaAttribute } from "../services/schema";
interface MapClassAttributesFnInput {
classObj: Partial<SchemaClass>;
attributes: Partial<SchemaAttributes>[];
attributes: Partial<SchemaAttribute>[];
}
interface AttributeFields {
dn: string;
attributeID: string;
attributeSyntax: string;
cn: string;
lDAPDisplayName: string;
isRequired: boolean;
isSingleValued: boolean;
systemOnly?: boolean;
adminDisplayName?: string;
adminDescription?: string;
}
export interface SchemaClassWithAttributes {
className: string;
ldapName: string;
parentClass: string;
/** direct parent class */
subClassOf: string;
/** ldap name of classes that this class inherits from */
auxiliaryClass?: string[];
systemAuxiliaryClass?: string[];
originalClassFields: Partial<SchemaClass>;
originalAttributes?: Partial<SchemaAttributes>[];
attributes?: Array<{
dn: string;
attributeID: string;
attributeSyntax: string;
cn: string;
adminDisplayName: string;
adminDescription: string;
isRequired: boolean;
isSingleValued: boolean;
lDAPDisplayName: string;
}>;
originalAttributes?: Partial<SchemaAttribute>[];
attributes?: AttributeFields[];
}
export declare function mapClassAttributes({ classObj, attributes, }: MapClassAttributesFnInput): SchemaClassWithAttributes;
export {};

@@ -10,3 +10,3 @@ "use strict";

ldapName: utils_1.stringifyProp(classObj.lDAPDisplayName),
parentClass: utils_1.stringifyProp(classObj.subClassOf),
subClassOf: utils_1.stringifyProp(classObj.subClassOf),
originalClassFields: Object.assign({}, classObj),

@@ -16,21 +16,52 @@ originalAttributes: [],

};
/** combine mustContain, systemMustContain, mayContain, and systemMayContain items to do search operation just one time */
/** add ldap name of auxiliary classes
* this field will define class interface should extends(inherits) from which class
*/
if (classObj.auxiliaryClass) {
result.auxiliaryClass = utils_1.arrayifyProp(classObj.auxiliaryClass);
}
/** add ldap name of systemAuxiliary classes
* this field will define class interface should extends(inherits) from which class
*/
if (classObj.systemAuxiliaryClass) {
result.systemAuxiliaryClass = utils_1.arrayifyProp(classObj.systemAuxiliaryClass);
}
/** place holder to keep combined
* mustContain, systemMustContain,
* mayContain, and systemMayContain
* items to do search operation just one time */
const combinedRawAttributes = [];
/**combine mustContain as required field*/
if (classObj.mustContain) {
utils_1.arrayifyProp(classObj.mustContain).forEach((attributeToFind) => combinedRawAttributes.push({ isRequired: true, attributeToFind }));
utils_1.arrayifyProp(classObj.mustContain).forEach((attributeToFind) => combinedRawAttributes.push({
isRequired: true,
isSystemProp: false,
attributeToFind,
}));
}
/**combine systemMustContain as required field*/
if (classObj.systemMustContain) {
utils_1.arrayifyProp(classObj.systemMustContain).forEach((attributeToFind) => combinedRawAttributes.push({ isRequired: true, attributeToFind }));
utils_1.arrayifyProp(classObj.systemMustContain).forEach((attributeToFind) => combinedRawAttributes.push({
isRequired: true,
isSystemProp: true,
attributeToFind,
}));
}
/**combine mayContain as non required field*/
if (classObj.mayContain) {
utils_1.arrayifyProp(classObj.mayContain).forEach((attributeToFind) => combinedRawAttributes.push({ isRequired: false, attributeToFind }));
utils_1.arrayifyProp(classObj.mayContain).forEach((attributeToFind) => combinedRawAttributes.push({
isRequired: false,
isSystemProp: false,
attributeToFind,
}));
}
/**combine systemMayContain as non required field*/
if (classObj.systemMayContain) {
utils_1.arrayifyProp(classObj.systemMayContain).forEach((attributeToFind) => combinedRawAttributes.push({ isRequired: false, attributeToFind }));
utils_1.arrayifyProp(classObj.systemMayContain).forEach((attributeToFind) => combinedRawAttributes.push({
isRequired: false,
isSystemProp: true,
attributeToFind,
}));
}
combinedRawAttributes.forEach(({ attributeToFind, isRequired }) => {
combinedRawAttributes.forEach(({ attributeToFind, isRequired, isSystemProp }) => {
var _a, _b;

@@ -45,3 +76,3 @@ /** search in attributes */

(_a = result.originalAttributes) === null || _a === void 0 ? void 0 : _a.push(foundAttribute);
(_b = result.attributes) === null || _b === void 0 ? void 0 : _b.push({
const classAttributes = {
dn: utils_1.stringifyProp(foundAttribute.dn),

@@ -52,7 +83,20 @@ cn: utils_1.stringifyProp(foundAttribute.cn),

attributeID: utils_1.stringifyProp(foundAttribute.attributeID),
adminDisplayName: utils_1.stringifyProp(foundAttribute.adminDisplayName),
adminDescription: utils_1.stringifyProp(foundAttribute.adminDescription),
isRequired,
isSingleValued: utils_1.ldapBooleanToJsBoolean(utils_1.stringifyProp(foundAttribute.isSingleValued)),
});
};
/** this field can be empty */
if (foundAttribute.adminDisplayName) {
classAttributes.adminDisplayName = utils_1.stringifyProp(foundAttribute.adminDisplayName);
}
/** this field can be empty */
if (foundAttribute.adminDescription) {
classAttributes.adminDescription = utils_1.stringifyProp(foundAttribute.adminDescription);
}
/** this field can be empty */
if (foundAttribute.systemOnly) {
const systemOnly = utils_1.ldapBooleanToJsBoolean(utils_1.stringifyProp(foundAttribute.systemOnly));
/** either systemOnly or isSystemProp this flag makes attribute in interface readonly */
classAttributes.systemOnly = systemOnly || isSystemProp;
}
(_b = result.attributes) === null || _b === void 0 ? void 0 : _b.push(classAttributes);
});

@@ -59,0 +103,0 @@ return result;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const fast_node_logger_1 = require("fast-node-logger");
/** for more info look at links below:
* - https://social.technet.microsoft.com/wiki/contents/articles/52570.active-directory-syntaxes-of-attributes.aspx
* - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/7cda533e-d7a4-4aec-a517-91d02ff4a1aa?redirectedfrom=MSDN
*/
const typeMap = {

@@ -19,6 +23,6 @@ string: [

boolean: ["2.5.5.8"],
number: ["2.5.5.16"],
number: ["2.5.5.16", "2.5.5.9"],
Date: ["2.5.5.11"],
/** ref: https://docs.microsoft.com/en-us/windows/win32/adschema/s-object-ds-dn */
object: ["2.5.5.1"],
Enum: ["2.5.5.9"],
};

@@ -25,0 +29,0 @@ /** get ldap attributeSyntax and return js equivalent type */

@@ -1,3 +0,7 @@

export declare function stringifyProp(input?: string | string[]): string;
export declare function arrayifyProp(input?: string | string[]): string[];
/** make sure output is string */
export declare function stringifyProp(input: string | string[]): string;
/** make sure output is array of strings */
export declare function arrayifyProp(input: string | string[]): string[];
export declare function ldapBooleanToJsBoolean(input: string): boolean;
/** convert array of strings to one string and add line break between each */
export declare function arrayToLines(data?: string[]): string;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const fast_node_logger_1 = require("fast-node-logger");
/** make sure output is string */
function stringifyProp(input) {
fast_node_logger_1.writeLog(`stringifyProp()`);
if (!input) {
throw new Error(`Field not exist`);
throw new Error(`Field required to stringify! but provided: ${input} `);
}

@@ -15,6 +16,7 @@ if (Array.isArray(input)) {

exports.stringifyProp = stringifyProp;
/** make sure output is array of strings */
function arrayifyProp(input) {
fast_node_logger_1.writeLog(`arrayifyProp()`);
if (!input) {
throw new Error(`Field not exist to arrayify`);
throw new Error(`Field required to arrayify`);
}

@@ -34,2 +36,10 @@ if (typeof input === "string") {

exports.ldapBooleanToJsBoolean = ldapBooleanToJsBoolean;
/** convert array of strings to one string and add line break between each */
function arrayToLines(data) {
if (!data) {
throw new Error(`data input required. but provided: ${data}`);
}
return data.join("\n");
}
exports.arrayToLines = arrayToLines;
//# sourceMappingURL=utils.js.map

@@ -5,20 +5,31 @@ import { Logger } from "../typings/general/types";

schemaDn: string;
logger?: Logger;
options: {
user: string;
pass: string;
ldapServerUrl: string;
logger?: Logger;
};
}
export interface SchemaClass extends SearchEntryObject {
export interface SchemaClass extends Pick<SearchEntryObject, "dn" | "controls"> {
objectClass: string | string[];
cn: string | string[];
cn: string;
instanceType: string | string[];
subClassOf: string | string[];
subClassOf: string;
auxiliaryClass?: string | string[];
systemAuxiliaryClass?: string | string[];
governsID: string | string[];
rDNAttID: string | string[];
showInAdvancedViewOnly: string | string[];
adminDisplayName: string | string[];
adminDescription: string | string[];
/** string value of TRUE / FALSE */
showInAdvancedViewOnly: string;
adminDisplayName: string;
adminDescription: string;
objectClassCategory: string | string[];
lDAPDisplayName: string | string[];
name: string | string[];
systemOnly: string | string[];
lDAPDisplayName: string;
name: string;
/** string value of TRUE / FALSE */
systemOnly: string;
systemPossSuperiors: string | string[];
/** list of direct optional and readonly properties */
systemMayContain: string | string[];
/** list of direct required and readonly properties */
systemMustContain: string | string[];

@@ -29,26 +40,37 @@ systemFlags: string | string[];

defaultObjectCategory: string | string[];
/** list of direct required and editable properties */
mustContain: string | string[];
/** list of direct optional and editable properties */
mayContain: string | string[];
possSuperiors: string | string[];
}
export declare function getSchemaClasses({ schemaDn, logger, }: GetSchemaClassesFnInput): Promise<Partial<SchemaClass>[]>;
export declare type GetSchemaClassesFnOutput = Promise<Partial<SchemaClass>[]>;
export declare function getSchemaClasses({ schemaDn, options, }: GetSchemaClassesFnInput): GetSchemaClassesFnOutput;
interface GetSchemaAttributesFnInput {
schemaDn: string;
logger?: Logger;
options: {
user: string;
pass: string;
ldapServerUrl: string;
logger?: Logger;
};
}
export interface SchemaAttributes extends SearchEntryObject {
cn: string | string[];
attributeID: string | string[];
attributeSyntax: string | string[];
isSingleValued: string | string[];
showInAdvancedViewOnly: string | string[];
adminDisplayName: string | string[];
adminDescription: string | string[];
export interface SchemaAttribute extends Pick<SearchEntryObject, "dn" | "controls"> {
cn: string;
attributeID: string;
attributeSyntax: string;
/** string value of TRUE / FALSE */
isSingleValued: string;
/** string value of TRUE / FALSE */
showInAdvancedViewOnly: string;
adminDisplayName: string;
adminDescription: string;
oMSyntax: string | string[];
lDAPDisplayName: string | string[];
systemOnly: string | string[];
lDAPDisplayName: string;
systemOnly: string;
systemFlags: string | string[];
objectCategory: string | string[];
}
export declare function getSchemaAttributes({ logger, schemaDn, }: GetSchemaAttributesFnInput): Promise<Partial<SchemaAttributes>[]>;
export declare type GetSchemaAttributesFnOutput = Promise<Partial<SchemaAttribute>[]>;
export declare function getSchemaAttributes({ schemaDn, options, }: GetSchemaAttributesFnInput): GetSchemaAttributesFnOutput;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const node_ad_ldap_1 = require("node-ad-ldap");
async function getSchemaClasses({ schemaDn, logger, }) {
var _a, _b, _c;
logger === null || logger === void 0 ? void 0 : logger.trace("getSchemaClasses()");
async function getSchemaClasses({ schemaDn, options, }) {
var _a;
(_a = options.logger) === null || _a === void 0 ? void 0 : _a.trace("getSchemaClasses()");
const adClient = new node_ad_ldap_1.AdClient({
bindDN: (_a = process.env.AD_USER) !== null && _a !== void 0 ? _a : "",
secret: (_b = process.env.AD_Pass) !== null && _b !== void 0 ? _b : "",
url: (_c = process.env.AD_URI) !== null && _c !== void 0 ? _c : "",
bindDN: options.user,
secret: options.pass,
url: options.ldapServerUrl,
baseDN: schemaDn,
logger,
logger: options.logger,
});

@@ -25,2 +25,4 @@ const objectClasses = await adClient.queryAttributes({

"subClassOf",
"auxiliaryClass",
"systemAuxiliaryClass",
"governsID",

@@ -52,11 +54,11 @@ "rDNAttID",

exports.getSchemaClasses = getSchemaClasses;
async function getSchemaAttributes({ logger, schemaDn, }) {
var _a, _b, _c;
logger === null || logger === void 0 ? void 0 : logger.trace("getSchemaAttributes()");
async function getSchemaAttributes({ schemaDn, options, }) {
var _a;
(_a = options.logger) === null || _a === void 0 ? void 0 : _a.trace("getSchemaAttributes()");
const adClient = new node_ad_ldap_1.AdClient({
bindDN: (_a = process.env.AD_USER) !== null && _a !== void 0 ? _a : "",
secret: (_b = process.env.AD_Pass) !== null && _b !== void 0 ? _b : "",
url: (_c = process.env.AD_URI) !== null && _c !== void 0 ? _c : "",
bindDN: options.user,
secret: options.pass,
url: options.ldapServerUrl,
baseDN: schemaDn,
logger,
logger: options.logger,
});

@@ -63,0 +65,0 @@ const objectAttributes = await adClient.queryAttributes({

{
"name": "ldap-schema-ts-generator",
"version": "0.1.0",
"description": "Ldap Active Directory Schema Typescript Generator",
"version": "0.9.9",
"description": "Ldap Active Directory Schema Typescript Interface Generator",
"repository": {

@@ -9,5 +9,4 @@ "type": "git",

},
"main": "dist/app.js",
"types": "dist/app.d.ts",
"bin": "bin/setup",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {

@@ -29,2 +28,5 @@ "format": "prettier --check \"src/**/*.ts\" --write",

"typescript",
"interface",
"type",
"definition",
"generator",

@@ -56,3 +58,2 @@ "type",

"npm-run-all": "^4.1.5",
"prettier": "^2.0.2",
"ts-jest": "^25.3.1",

@@ -65,4 +66,6 @@ "typescript": "^3.8.3"

"fast-node-logger": "^1.3.3",
"node-ad-ldap": "^1.3.0"
"node-ad-ldap": "^1.3.0",
"pascal-case": "^3.1.1",
"prettier": "^2.0.2"
}
}
# Ldap Active Directory Schema Typescript Generator
### How to use
```ts
import {
getSchemaAttributes,
getSchemaClasses,
generateInterfaceFiles,
} from "./index";
async function main() {
const schemaDn = "CN=Schema,CN=Configuration,DC=ki,DC=local";
const options = {
user: process.env.AD_USER ?? "",
pass: process.env.AD_Pass ?? "",
ldapServerUrl: process.env.AD_URI ?? "",
};
const objectAttributes = await getSchemaAttributes({ schemaDn, options });
const objectClasses = await getSchemaClasses({ schemaDn, options });
await generateInterfaceFiles({ objectAttributes, objectClasses });
}
main().catch((err) => {
console.log(err);
});
```
### Result
creates typescript interface for each LDAP class that exist in schema
### Sample:
```ts Account.ts
import { Top } from "./Top";
/** - object class: account
* - child of class: top
* - dn: CN=account,CN=Schema,CN=Configuration,DC=ki,DC=local
*/
export interface Account extends Top {
/** - attributeSyntax: 2.5.5.12
* - attributeID: 0.9.2342.19200300.100.1.1
* - adminDisplayName: uid
* - adminDescription: A user ID.
* - dn: CN=uid,CN=Schema,CN=Configuration,DC=ki,DC=local
*/
uid?: string[];
/** - attributeSyntax: 2.5.5.12
* - attributeID: 0.9.2342.19200300.100.1.9
* - adminDisplayName: host
* - adminDescription: The host attribute type specifies a host computer.
* - dn: CN=host,CN=Schema,CN=Configuration,DC=ki,DC=local
*/
host?: string[];
/** - attributeSyntax: 2.5.5.12
* - attributeID: 2.5.4.11
* - adminDisplayName: Organizational-Unit-Name
* - adminDescription: Organizational-Unit-Name
* - dn: CN=Organizational-Unit-Name,CN=Schema,CN=Configuration,DC=ki,DC=local
*/
ou?: string[];
/** - attributeSyntax: 2.5.5.12
* - attributeID: 2.5.4.10
* - adminDisplayName: Organization-Name
* - adminDescription: Organization-Name
* - dn: CN=Organization-Name,CN=Schema,CN=Configuration,DC=ki,DC=local
*/
o?: string[];
/** - attributeSyntax: 2.5.5.12
* - attributeID: 2.5.4.7
* - adminDisplayName: Locality-Name
* - adminDescription: Locality-Name
* - dn: CN=Locality-Name,CN=Schema,CN=Configuration,DC=ki,DC=local
*/
l?: string;
/** - attributeSyntax: 2.5.5.1
* - attributeID: 2.5.4.34
* - adminDisplayName: See-Also
* - adminDescription: See-Also
* - dn: CN=See-Also,CN=Schema,CN=Configuration,DC=ki,DC=local
*/
seeAlso?: object[];
/** - attributeSyntax: 2.5.5.12
* - attributeID: 2.5.4.13
* - adminDisplayName: Description
* - adminDescription: Description
* - dn: CN=Description,CN=Schema,CN=Configuration,DC=ki,DC=local
*/
description?: string[];
}
```
### Options:
```ts
options?: {
/** default generated folder of root directory of you project */
outputFolder?: string;
/** use prettier to format generated files. default true */
usePrettier?: boolean;
/** create index file for output folder. default true */
indexFile: boolean;
};
```
import { config } from "dotenv";
config();
import { createLogger } from "fast-node-logger";
import { getSchemaAttributes, getSchemaClasses } from "./services/schema";
import { mapClassAttributes } from "./helpers/map-class-attributes";
import fs from "fs";
import path from "path";
import { generate } from "./helpers/generateText";
import prettier from "prettier";
config();
import {
getSchemaAttributes,
getSchemaClasses,
generateInterfaceFiles,
} from "./index";
/**
* 1- get list of objectClass=classSchema
* 2 get list of objectClass=attributeSchema
* 3-1 look at mustContain, systemMustContain, mayContain, and systemMayContain
* 3-2 map attributes with class object
*/
const schemaDn = "CN=Schema,CN=Configuration,DC=ki,DC=local";
async function main() {
const logger = await createLogger({ level: "trace" });
const objectAttributes = await getSchemaAttributes({ schemaDn, logger });
const schemaDn = "CN=Schema,CN=Configuration,DC=ki,DC=local";
const options = {
user: process.env.AD_USER ?? "",
pass: process.env.AD_Pass ?? "",
ldapServerUrl: process.env.AD_URI ?? "",
logger,
};
const objectClasses = await getSchemaClasses({ schemaDn, logger });
const objectAttributes = await getSchemaAttributes({ schemaDn, options });
const classWithAttributes = mapClassAttributes({
attributes: objectAttributes,
classObj: objectClasses[0],
});
const objectClasses = await getSchemaClasses({ schemaDn, options });
/** now we have everything we need
* it's time to generate typescript types:
* 1- create handlebar template
* 2- generate type for each attribute
* 3- generate type for each class
* 4- maybe create a class for class object and pre-define CRUD operation like ORM
*/
const rawOutput = generate({ data: classWithAttributes });
/** run prettier at output before write to file */
const output = prettier.format(rawOutput, { parser: "typescript" });
/** write to file.
* over write if exist
*/
fs.writeFileSync(path.join(process.cwd(), "generated", "out.ts"), output, {
encoding: "utf8",
flag: "w",
});
await generateInterfaceFiles({ objectAttributes, objectClasses });
}

@@ -53,0 +27,0 @@ main().catch((err) => {

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

import type { SchemaClass, SchemaAttributes } from "../services/schema";
import type { SchemaClass, SchemaAttribute } from "../services/schema";
import { writeLog } from "fast-node-logger";

@@ -7,22 +7,28 @@ import { stringifyProp, arrayifyProp, ldapBooleanToJsBoolean } from "./utils";

classObj: Partial<SchemaClass>;
attributes: Partial<SchemaAttributes>[];
attributes: Partial<SchemaAttribute>[];
}
interface AttributeFields {
dn: string;
attributeID: string;
attributeSyntax: string;
cn: string;
lDAPDisplayName: string;
isRequired: boolean;
isSingleValued: boolean;
systemOnly?: boolean;
adminDisplayName?: string;
adminDescription?: string;
}
export interface SchemaClassWithAttributes {
className: string;
ldapName: string;
parentClass: string;
/** direct parent class */
subClassOf: string;
/** ldap name of classes that this class inherits from */
auxiliaryClass?: string[];
systemAuxiliaryClass?: string[];
originalClassFields: Partial<SchemaClass>;
originalAttributes?: Partial<SchemaAttributes>[];
attributes?: Array<{
dn: string;
attributeID: string;
attributeSyntax: string;
cn: string;
adminDisplayName: string;
adminDescription: string;
isRequired: boolean;
isSingleValued: boolean;
lDAPDisplayName: string;
}>;
originalAttributes?: Partial<SchemaAttribute>[];
attributes?: AttributeFields[];
}

@@ -36,5 +42,5 @@

const result: SchemaClassWithAttributes = {
className: stringifyProp(classObj.name),
ldapName: stringifyProp(classObj.lDAPDisplayName),
parentClass: stringifyProp(classObj.subClassOf),
className: stringifyProp(classObj.name as string),
ldapName: stringifyProp(classObj.lDAPDisplayName as string),
subClassOf: stringifyProp(classObj.subClassOf as string),
originalClassFields: { ...classObj },

@@ -45,5 +51,24 @@ originalAttributes: [],

/** combine mustContain, systemMustContain, mayContain, and systemMayContain items to do search operation just one time */
/** add ldap name of auxiliary classes
* this field will define class interface should extends(inherits) from which class
*/
if (classObj.auxiliaryClass) {
result.auxiliaryClass = arrayifyProp(classObj.auxiliaryClass);
}
/** add ldap name of systemAuxiliary classes
* this field will define class interface should extends(inherits) from which class
*/
if (classObj.systemAuxiliaryClass) {
result.systemAuxiliaryClass = arrayifyProp(classObj.systemAuxiliaryClass);
}
/** place holder to keep combined
* mustContain, systemMustContain,
* mayContain, and systemMayContain
* items to do search operation just one time */
const combinedRawAttributes: Array<{
isRequired: boolean;
/** true when source of attribute is systemMustContain or systemMayContain (attribute should be readonly) */
isSystemProp: boolean;
attributeToFind: string;

@@ -55,3 +80,7 @@ }> = [];

arrayifyProp(classObj.mustContain).forEach((attributeToFind) =>
combinedRawAttributes.push({ isRequired: true, attributeToFind }),
combinedRawAttributes.push({
isRequired: true,
isSystemProp: false,
attributeToFind,
}),
);

@@ -62,3 +91,7 @@ }

arrayifyProp(classObj.systemMustContain).forEach((attributeToFind) =>
combinedRawAttributes.push({ isRequired: true, attributeToFind }),
combinedRawAttributes.push({
isRequired: true,
isSystemProp: true,
attributeToFind,
}),
);

@@ -69,3 +102,7 @@ }

arrayifyProp(classObj.mayContain).forEach((attributeToFind) =>
combinedRawAttributes.push({ isRequired: false, attributeToFind }),
combinedRawAttributes.push({
isRequired: false,
isSystemProp: false,
attributeToFind,
}),
);

@@ -76,34 +113,70 @@ }

arrayifyProp(classObj.systemMayContain).forEach((attributeToFind) =>
combinedRawAttributes.push({ isRequired: false, attributeToFind }),
combinedRawAttributes.push({
isRequired: false,
isSystemProp: true,
attributeToFind,
}),
);
}
combinedRawAttributes.forEach(({ attributeToFind, isRequired }) => {
/** search in attributes */
//TODO: this is an expensive operation there should be better way to improve it
const foundAttribute = attributes.find(
(attributeItem) => attributeItem.lDAPDisplayName === attributeToFind,
);
if (!foundAttribute) {
throw new Error(`Attribute ${attributeToFind} not found!`);
}
combinedRawAttributes.forEach(
({ attributeToFind, isRequired, isSystemProp }) => {
/** search in attributes */
//TODO: this is an expensive operation there should be better way to improve it
const foundAttribute = attributes.find(
(attributeItem) => attributeItem.lDAPDisplayName === attributeToFind,
);
/**push found attribute */
result.originalAttributes?.push(foundAttribute);
result.attributes?.push({
dn: stringifyProp(foundAttribute.dn),
cn: stringifyProp(foundAttribute.cn),
lDAPDisplayName: stringifyProp(foundAttribute.lDAPDisplayName),
attributeSyntax: stringifyProp(foundAttribute.attributeSyntax),
attributeID: stringifyProp(foundAttribute.attributeID),
adminDisplayName: stringifyProp(foundAttribute.adminDisplayName),
adminDescription: stringifyProp(foundAttribute.adminDescription),
isRequired,
isSingleValued: ldapBooleanToJsBoolean(
stringifyProp(foundAttribute.isSingleValued),
),
});
});
if (!foundAttribute) {
throw new Error(`Attribute ${attributeToFind} not found!`);
}
/**push found attribute */
result.originalAttributes?.push(foundAttribute);
const classAttributes: AttributeFields = {
dn: stringifyProp(foundAttribute.dn as string),
cn: stringifyProp(foundAttribute.cn as string),
lDAPDisplayName: stringifyProp(
foundAttribute.lDAPDisplayName as string,
),
attributeSyntax: stringifyProp(
foundAttribute.attributeSyntax as string,
),
attributeID: stringifyProp(foundAttribute.attributeID as string),
isRequired,
isSingleValued: ldapBooleanToJsBoolean(
stringifyProp(foundAttribute.isSingleValued as string),
),
};
/** this field can be empty */
if (foundAttribute.adminDisplayName) {
classAttributes.adminDisplayName = stringifyProp(
foundAttribute.adminDisplayName as string,
);
}
/** this field can be empty */
if (foundAttribute.adminDescription) {
classAttributes.adminDescription = stringifyProp(
foundAttribute.adminDescription as string,
);
}
/** this field can be empty */
if (foundAttribute.systemOnly) {
const systemOnly = ldapBooleanToJsBoolean(
stringifyProp(foundAttribute.systemOnly),
);
/** either systemOnly or isSystemProp this flag makes attribute in interface readonly */
classAttributes.systemOnly = systemOnly || isSystemProp;
}
result.attributes?.push(classAttributes);
},
);
return result;
}
import { writeLog } from "fast-node-logger";
/** for more info look at links below:
* - https://social.technet.microsoft.com/wiki/contents/articles/52570.active-directory-syntaxes-of-attributes.aspx
* - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/7cda533e-d7a4-4aec-a517-91d02ff4a1aa?redirectedfrom=MSDN
*/
const typeMap = {

@@ -18,6 +23,6 @@ string: [

boolean: ["2.5.5.8"],
number: ["2.5.5.16"],
number: ["2.5.5.16", "2.5.5.9"],
Date: ["2.5.5.11"],
/** ref: https://docs.microsoft.com/en-us/windows/win32/adschema/s-object-ds-dn */
object: ["2.5.5.1"],
Enum: ["2.5.5.9"],
};

@@ -24,0 +29,0 @@

import { writeLog } from "fast-node-logger";
export function stringifyProp(input?: string | string[]): string {
/** make sure output is string */
export function stringifyProp(input: string | string[]): string {
writeLog(`stringifyProp()`);
if (!input) {
throw new Error(`Field not exist`);
throw new Error(`Field required to stringify! but provided: ${input} `);
}

@@ -14,6 +15,7 @@ if (Array.isArray(input)) {

export function arrayifyProp(input?: string | string[]): string[] {
/** make sure output is array of strings */
export function arrayifyProp(input: string | string[]): string[] {
writeLog(`arrayifyProp()`);
if (!input) {
throw new Error(`Field not exist to arrayify`);
throw new Error(`Field required to arrayify`);
}

@@ -32,1 +34,9 @@ if (typeof input === "string") {

}
/** convert array of strings to one string and add line break between each */
export function arrayToLines(data?: string[]): string {
if (!data) {
throw new Error(`data input required. but provided: ${data}`);
}
return data.join("\n");
}

@@ -7,20 +7,32 @@ import { AdClient } from "node-ad-ldap";

schemaDn: string;
logger?: Logger;
options: {
user: string;
pass: string;
ldapServerUrl: string;
logger?: Logger;
};
}
export interface SchemaClass extends SearchEntryObject {
export interface SchemaClass
extends Pick<SearchEntryObject, "dn" | "controls"> {
objectClass: string | string[];
cn: string | string[];
cn: string;
instanceType: string | string[];
subClassOf: string | string[];
subClassOf: string;
auxiliaryClass?: string | string[];
systemAuxiliaryClass?: string | string[];
governsID: string | string[];
rDNAttID: string | string[];
showInAdvancedViewOnly: string | string[];
adminDisplayName: string | string[];
adminDescription: string | string[];
/** string value of TRUE / FALSE */
showInAdvancedViewOnly: string;
adminDisplayName: string;
adminDescription: string;
objectClassCategory: string | string[];
lDAPDisplayName: string | string[];
name: string | string[];
systemOnly: string | string[];
lDAPDisplayName: string;
name: string;
/** string value of TRUE / FALSE */
systemOnly: string;
systemPossSuperiors: string | string[];
/** list of direct optional and readonly properties */
systemMayContain: string | string[];
/** list of direct required and readonly properties */
systemMustContain: string | string[];

@@ -31,3 +43,5 @@ systemFlags: string | string[];

defaultObjectCategory: string | string[];
/** list of direct required and editable properties */
mustContain: string | string[];
/** list of direct optional and editable properties */
mayContain: string | string[];

@@ -37,13 +51,14 @@ possSuperiors: string | string[];

export type GetSchemaClassesFnOutput = Promise<Partial<SchemaClass>[]>;
export async function getSchemaClasses({
schemaDn,
logger,
}: GetSchemaClassesFnInput): Promise<Partial<SchemaClass>[]> {
logger?.trace("getSchemaClasses()");
options,
}: GetSchemaClassesFnInput): GetSchemaClassesFnOutput {
options.logger?.trace("getSchemaClasses()");
const adClient = new AdClient({
bindDN: process.env.AD_USER ?? "",
secret: process.env.AD_Pass ?? "",
url: process.env.AD_URI ?? "",
bindDN: options.user,
secret: options.pass,
url: options.ldapServerUrl,
baseDN: schemaDn,
logger,
logger: options.logger,
});

@@ -62,2 +77,4 @@

"subClassOf",
"auxiliaryClass",
"systemAuxiliaryClass",
"governsID",

@@ -91,15 +108,23 @@ "rDNAttID",

schemaDn: string;
logger?: Logger;
options: {
user: string;
pass: string;
ldapServerUrl: string;
logger?: Logger;
};
}
export interface SchemaAttributes extends SearchEntryObject {
cn: string | string[];
attributeID: string | string[];
attributeSyntax: string | string[];
isSingleValued: string | string[];
showInAdvancedViewOnly: string | string[];
adminDisplayName: string | string[];
adminDescription: string | string[];
export interface SchemaAttribute
extends Pick<SearchEntryObject, "dn" | "controls"> {
cn: string;
attributeID: string;
attributeSyntax: string;
/** string value of TRUE / FALSE */
isSingleValued: string;
/** string value of TRUE / FALSE */
showInAdvancedViewOnly: string;
adminDisplayName: string;
adminDescription: string;
oMSyntax: string | string[];
lDAPDisplayName: string | string[];
systemOnly: string | string[];
lDAPDisplayName: string;
systemOnly: string;
systemFlags: string | string[];

@@ -109,13 +134,14 @@ objectCategory: string | string[];

export type GetSchemaAttributesFnOutput = Promise<Partial<SchemaAttribute>[]>;
export async function getSchemaAttributes({
logger,
schemaDn,
}: GetSchemaAttributesFnInput): Promise<Partial<SchemaAttributes>[]> {
logger?.trace("getSchemaAttributes()");
options,
}: GetSchemaAttributesFnInput): GetSchemaAttributesFnOutput {
options.logger?.trace("getSchemaAttributes()");
const adClient = new AdClient({
bindDN: process.env.AD_USER ?? "",
secret: process.env.AD_Pass ?? "",
url: process.env.AD_URI ?? "",
bindDN: options.user,
secret: options.pass,
url: options.ldapServerUrl,
baseDN: schemaDn,
logger,
logger: options.logger,
});

@@ -122,0 +148,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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