Basic server setup

This commit is contained in:
Douglas Barone 2023-12-15 15:55:53 -04:00
parent 60af230a2d
commit 68273802cc
9 changed files with 182 additions and 41 deletions

3
.gitignore vendored
View File

@ -2,7 +2,6 @@
node_modules
/dist
# local env files
.env.local
.env.*.local
@ -21,3 +20,5 @@ pnpm-debug.log*
*.njsproj
*.sln
*.sw?
.env

14
.prettierrc Executable file
View File

@ -0,0 +1,14 @@
{
"trailingComma": "none",
"tabWidth": 2,
"semi": false,
"singleQuote": true,
"bracketSpacing": true,
"arrowParens": "avoid",
"overrides": [
{
"files": "*.js, *.vue, *.css, *.scss",
"excludeFiles": "**/dist/**, **/node_modules/**"
}
]
}

View File

@ -1,44 +1,17 @@
# default
# IFMS Password updater - Web
## Project setup
```
# yarn
yarn
# npm
npm install
# pnpm
pnpm install
```
### Compiles and hot-reloads for development
```
# yarn
yarn dev
# npm
npm run dev
# pnpm
pnpm dev
```
npm run dev
### Compiles and minifies for production
```
# yarn
yarn build
# npm
npm run build
# pnpm
pnpm build
```
### Customize configuration
See [Configuration Reference](https://vitejs.dev/config/).

75
package-lock.json generated
View File

@ -13,7 +13,9 @@
"@trpc/server": "^10.44.1",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"ldapts": "^7.0.7",
"roboto-fontface": "*",
"vue": "^3.2.0",
"vue-router": "^4.0.0",
@ -589,6 +591,14 @@
"node": ">=18.0.0"
}
},
"node_modules/@types/asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@types/asn1/-/asn1-0.2.4.tgz",
"integrity": "sha512-V91DSJ2l0h0gRhVP4oBfBzRBN9lAbPUkGDMCnwedqPKX2d84aAMc9CulOvxdw1f7DfEYx99afab+Rsm3e52jhA==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/body-parser": {
"version": "1.19.5",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
@ -663,7 +673,6 @@
"version": "18.19.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz",
"integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==",
"devOptional": true,
"dependencies": {
"undici-types": "~5.26.4"
}
@ -707,6 +716,11 @@
"@types/node": "*"
}
},
"node_modules/@types/uuid": {
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz",
"integrity": "sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g=="
},
"node_modules/@types/webfontloader": {
"version": "1.6.38",
"resolved": "https://registry.npmjs.org/@types/webfontloader/-/webfontloader-1.6.38.tgz",
@ -1235,6 +1249,14 @@
"node": ">=8"
}
},
"node_modules/asn1": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
"dependencies": {
"safer-buffer": "~2.1.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -1544,7 +1566,6 @@
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"devOptional": true,
"dependencies": {
"ms": "2.1.2"
},
@ -1617,6 +1638,17 @@
"node": ">=6.0.0"
}
},
"node_modules/dotenv": {
"version": "16.3.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
"integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/motdotla/dotenv?sponsor=1"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -2568,6 +2600,22 @@
"json-buffer": "3.0.1"
}
},
"node_modules/ldapts": {
"version": "7.0.7",
"resolved": "https://registry.npmjs.org/ldapts/-/ldapts-7.0.7.tgz",
"integrity": "sha512-c/W9jZJ2WiGiAIBnkzUmYkIw1d5jebfVfp+vpR9Z6xh4QXm+kwwaQbmHFJHKsW4OwFARdOaQ03H3fBky4+XcVg==",
"dependencies": {
"@types/asn1": ">=0.2.4",
"@types/uuid": ">=9",
"asn1": "~0.2.6",
"debug": "~4.3.4",
"strict-event-emitter-types": "~2.0.0",
"uuid": "~9.0.1"
},
"engines": {
"node": ">=18"
}
},
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@ -2743,8 +2791,7 @@
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"devOptional": true
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/muggle-string": {
"version": "0.3.1",
@ -3471,6 +3518,11 @@
"node": ">= 0.8"
}
},
"node_modules/strict-event-emitter-types": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strict-event-emitter-types/-/strict-event-emitter-types-2.0.0.tgz",
"integrity": "sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA=="
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@ -3657,8 +3709,7 @@
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"devOptional": true
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
},
"node_modules/unpipe": {
"version": "1.0.0",
@ -3701,6 +3752,18 @@
"node": ">= 0.4.0"
}
},
"node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",

View File

@ -19,7 +19,9 @@
"@trpc/server": "^10.44.1",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"ldapts": "^7.0.7",
"roboto-fontface": "*",
"vue": "^3.2.0",
"vue-router": "^4.0.0",

View File

@ -1,3 +1,5 @@
import "dotenv/config";
import { server } from "./server";
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

View File

@ -0,0 +1,12 @@
export function encodePassword(password: string): string {
let encodedPassword = "";
password = '"' + password + '"';
for (let i = 0; i < password.length; i++)
encodedPassword += String.fromCharCode(
password.charCodeAt(i) & 0xff,
(password.charCodeAt(i) >>> 8) & 0xff
);
return encodedPassword;
}

View File

@ -0,0 +1,66 @@
import { Client, Change, Attribute } from 'ldapts'
import { encodePassword } from './encodePassword'
const ldapClient = new Client({
url: process.env.LDAP_URL || 'ldap://10.1.0.16'
})
const bindUser = process.env.AD_BIND_USER || ''
const bindPassword = process.env.AD_BIND_PASSWORD || ''
const baseDN = process.env.AD_BASE_DN || ''
async function getUserDN(username: string): Promise<string> {
try {
await ldapClient.bind(bindUser, bindPassword)
const { searchEntries } = await ldapClient.search(baseDN, {
scope: 'sub',
attributes: ['dn'],
filter: `(sAMAccountName=${username})`
})
return searchEntries[0]?.dn
} catch (err) {
console.error(err)
} finally {
await ldapClient.unbind()
}
throw new Error('User not found')
}
export async function updatePassword({
username,
password,
newPassword
}: {
username: string
password: string
newPassword: string
}) {
try {
const userDN = await getUserDN(username)
await ldapClient.bind(userDN, password)
await ldapClient.modify(userDN, [
new Change({
operation: 'delete',
modification: new Attribute({
type: 'unicodePwd',
values: [encodePassword(password)]
})
}),
new Change({
operation: 'add',
modification: new Attribute({
type: 'unicodePwd',
values: [encodePassword(newPassword)]
})
})
])
} catch (err) {
console.error(err)
} finally {
await ldapClient.unbind()
}
}

View File

@ -1,16 +1,24 @@
import { initTRPC, TRPCError } from "@trpc/server";
import * as trpcExpress from "@trpc/server/adapters/express";
// import { z } from "zod";
import { z } from "zod";
export const t = initTRPC.create();
export const { procedure, router } = initTRPC.create();
const { query, mutation, input } = t.procedure;
const { query, mutation, input } = procedure;
export const appRouter = t.router({
export const appRouter = router({
hello: query(async () => {
return "Hello World!";
}),
updatePassword: input(
z.object({
username: z.string(),
password: z.string(),
newPassword: z.string().min(8),
})
).mutation(async () => {}),
});
// export type definition of API