Compare commits
94
Commits
hybrid-redmine
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b01ba5397e | ||
|
|
97e6fb83b5 | ||
|
|
9a1d260afe | ||
|
|
d4c9b722d2 | ||
|
|
f7b5a35bee | ||
|
|
0553d08007 | ||
|
|
c68a482c29 | ||
|
|
fcc2a9a003 | ||
|
|
da0e3108ca | ||
|
|
efdba4ccc2 | ||
|
|
6915b7d230 | ||
|
|
24297a1206 | ||
|
|
be70f43151 | ||
|
|
a89b8821c8 | ||
|
|
5dfe2d1fb8 | ||
|
|
6377554897 | ||
|
|
c24e66369a | ||
|
|
ae254fe7dd | ||
|
|
da456449b8 | ||
|
|
43ee1de9af | ||
|
|
28231a81b4 | ||
|
|
62de556327 | ||
|
|
24413e64b0 | ||
|
|
977332680c | ||
|
|
d9ad874401 | ||
|
|
26aecd3264 | ||
|
|
90f2b53d1c | ||
|
|
6812a952b8 | ||
|
|
9437fb2878 | ||
|
|
698ef50288 | ||
|
|
b7e8045b22 | ||
|
|
8dc7de8944 | ||
|
|
32fed53f5a | ||
|
|
96b32f385e | ||
|
|
e50b60be8e | ||
|
|
e1172afaa4 | ||
|
|
6fef2007d4 | ||
|
|
799dc363f5 | ||
|
|
978bd95afe | ||
|
|
ab99896b1e | ||
|
|
f9e86c50c6 | ||
|
|
6acd1824f9 | ||
|
|
ee087eb744 | ||
|
|
3cf7def67a | ||
|
|
0a0aef8712 | ||
|
|
ace9e436ee | ||
|
|
45d0cf7061 | ||
|
|
978d905bd9 | ||
|
|
8b8da3534b | ||
|
|
8f79886eb8 | ||
|
|
3d9b4a1964 | ||
|
|
4bc46dd8d1 | ||
|
|
311df6c79b | ||
|
|
3e7de5a626 | ||
|
|
54451a32a7 | ||
|
|
b7809a683b | ||
|
|
f8ca647e75 | ||
|
|
5bac7cd4f0 | ||
|
|
6af53ab82e | ||
|
|
2b2b424dec | ||
|
|
c86a100575 | ||
|
|
331b602e86 | ||
|
|
5fce11bc69 | ||
|
|
744a26316a | ||
|
|
37f2179f28 | ||
|
|
9fb8e2f6e4 | ||
|
|
b10596c0c6 | ||
|
|
0e95f1cb7b | ||
|
|
a30daf40dc | ||
|
|
2f228a0bd7 | ||
|
|
3bbfdbdb83 | ||
|
|
3e2e1301b8 | ||
|
|
7bd09115da | ||
|
|
fc602853a8 | ||
|
|
3579f248f2 | ||
|
|
87051c6ccb | ||
|
|
3af1eefd04 | ||
|
|
48230b96f9 | ||
|
|
f181bd6428 | ||
|
|
be761d99fd | ||
|
|
c283a75fc8 | ||
|
|
1af2064177 | ||
|
|
6a70b3d4f5 | ||
|
|
09f4c5a678 | ||
|
|
92281a0fb7 | ||
|
|
ab9559e8c6 | ||
|
|
916570e50e | ||
|
|
9b99688cfc | ||
|
|
bc3385dbaa | ||
|
|
3996ac1f60 | ||
|
|
de0dfafd43 | ||
|
|
06f4933e59 | ||
|
|
4d2f0adbff | ||
|
|
fe779bca77 |
@@ -0,0 +1,10 @@
|
||||
.git
|
||||
.gitlab-ci.yml
|
||||
Jenkinsfile.deprecated
|
||||
startgcpdevapi.sh
|
||||
.gitea
|
||||
node_modules
|
||||
scan
|
||||
debian
|
||||
tools
|
||||
*.tgz
|
||||
@@ -0,0 +1,61 @@
|
||||
name: Build + push image
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY: gitea.saas.vnc.biz
|
||||
IMAGE: gitea.saas.vnc.biz/vnclagoon/vnc-hybridauth-api
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
||||
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Compute image tag
|
||||
run: |
|
||||
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-8)
|
||||
echo "SHORT_SHA=${SHORT_SHA}" >> $GITHUB_ENV
|
||||
|
||||
# kaniko builds straight from a Dockerfile and pushes to the registry, running
|
||||
# as a static binary inside the job container — the runner has no Docker daemon.
|
||||
- name: Fetch kaniko (daemon-less image builder)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
curl -fsSL -o /tmp/crane.tgz \
|
||||
https://github.com/google/go-containerregistry/releases/download/v0.21.9/go-containerregistry_Linux_x86_64.tar.gz
|
||||
tar -xzf /tmp/crane.tgz -C /usr/local/bin crane
|
||||
mkdir -p /tmp/kaniko-root
|
||||
crane export gcr.io/kaniko-project/executor:debug /tmp/kaniko-fs.tar
|
||||
tar -xf /tmp/kaniko-fs.tar -C /tmp/kaniko-root
|
||||
cp /tmp/kaniko-root/kaniko/executor /usr/local/bin/kaniko-executor
|
||||
chmod +x /usr/local/bin/kaniko-executor
|
||||
/usr/local/bin/kaniko-executor version
|
||||
|
||||
# kaniko's push auth reads $DOCKER_CONFIG/config.json (go-containerregistry
|
||||
# authn.DefaultKeychain). Write to both locations and export DOCKER_CONFIG so
|
||||
# auth is picked up regardless of how $HOME resolves.
|
||||
- name: Configure registry auth for push
|
||||
run: |
|
||||
AUTH=$(printf '%s:%s' "${REGISTRY_USER}" "${REGISTRY_TOKEN}" | base64 -w0)
|
||||
CFG=$(printf '{"auths":{"%s":{"auth":"%s"}}}' "${REGISTRY}" "${AUTH}")
|
||||
mkdir -p /kaniko/.docker "$HOME/.docker"
|
||||
printf '%s' "$CFG" > /kaniko/.docker/config.json
|
||||
printf '%s' "$CFG" > "$HOME/.docker/config.json"
|
||||
echo "DOCKER_CONFIG=/kaniko/.docker" >> "$GITHUB_ENV"
|
||||
|
||||
# The Dockerfile lives at the repo root; its ADD/COPY paths (app/, package.json,
|
||||
# yarn.lock, config.js) are relative to the root.
|
||||
- name: Build + push image
|
||||
run: |
|
||||
/usr/local/bin/kaniko-executor \
|
||||
--context "dir://${GITHUB_WORKSPACE}" \
|
||||
--dockerfile Dockerfile \
|
||||
--skip-tls-verify-registry="${REGISTRY}" \
|
||||
--destination "${IMAGE}:sha-${SHORT_SHA}" \
|
||||
--destination "${IMAGE}:latest"
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
FROM alpine:3.22.4 AS builder
|
||||
|
||||
RUN apk update
|
||||
RUN apk update && apk upgrade && apk add --no-cache make gcc nodejs npm python3 g++ gcc libc-dev expat-dev libxml2-dev libxmlb-dev yarn nodejs-dev && rm -rf /var/cache/apk/*
|
||||
|
||||
RUN mkdir -p /usr/share/vnctalk-hybrid-authenticator2
|
||||
RUN mkdir -p /usr/share/vnctalk-hybrid-authenticator2/config
|
||||
ADD app /usr/share/vnctalk-hybrid-authenticator2/app
|
||||
|
||||
COPY package.json /usr/share/vnctalk-hybrid-authenticator2/package.json
|
||||
COPY yarn.lock /usr/share/vnctalk-hybrid-authenticator2/yarn.lock
|
||||
COPY config.js /usr/share/vnctalk-hybrid-authenticator2/config/vnc-hybrid-authenticator.js
|
||||
|
||||
RUN cd /usr/share/vnctalk-hybrid-authenticator2 && yarn install
|
||||
|
||||
FROM alpine:3.22.4
|
||||
|
||||
RUN apk update && apk upgrade && apk add --no-cache nodejs npm expat libxml2 libxmlb && rm -rf /var/cache/apk/*
|
||||
|
||||
COPY --from=builder /usr/share/vnctalk-hybrid-authenticator2 /usr/share/vnctalk-hybrid-authenticator2
|
||||
# Create non-root user and transfer ownership
|
||||
RUN addgroup -g 1001 vncuser && \
|
||||
adduser -D -u 1001 -G vncuser vncuser
|
||||
|
||||
USER vncuser
|
||||
|
||||
|
||||
LABEL org.opencontainers.image.source=https://github.com/vnc-biz/vnclagoon-images
|
||||
|
||||
#RUN npm install /usr/share/vnctalk-hybrid-authenticator2/app
|
||||
|
||||
CMD ["node", "/usr/share/vnctalk-hybrid-authenticator2/app/app.js"]
|
||||
|
||||
Vendored
-63
@@ -1,63 +0,0 @@
|
||||
#!groovy
|
||||
|
||||
pipeline {
|
||||
agent none
|
||||
|
||||
environment {
|
||||
git_commit_message = ''
|
||||
git_commit_diff = ''
|
||||
git_commit_author = ''
|
||||
git_commit_author_name = ''
|
||||
git_commit_author_email = ''
|
||||
ANDROID_HOME = '/opt/android-sdk/'
|
||||
}
|
||||
|
||||
stages {
|
||||
|
||||
stage('Packaging') {
|
||||
agent {
|
||||
label 'master'
|
||||
}
|
||||
steps {
|
||||
sh "echo 'Packaging'"
|
||||
deleteDir()
|
||||
checkout scm
|
||||
sh "git fetch --tags"
|
||||
sh "makechangelog.uxf > debian/changelog"
|
||||
sh "cat debian/changelog"
|
||||
sh "mkdir src"
|
||||
sh "sed -n 1p debian/changelog | grep -oP '\\((.*?)\\)' > src/version.txt"
|
||||
sh "echo '####################################################'"
|
||||
sh "cat src/version.txt"
|
||||
sh "echo '####################################################'"
|
||||
|
||||
sh 'rm config/vnc-hybrid-authenticator.js'
|
||||
sh 'cp -P conf.template/vnc-hybridauth2.js config/vnc-hybrid-authenticator.js'
|
||||
// yarn fails on node4 with kurento stuff
|
||||
sh 'yarn install'
|
||||
lock('debianbuild') {
|
||||
sh "cd debian; debuild --check-dirname-level 0 --no-tgz-check --no-lintian -kjenkins@vnc.biz -p'gpg --no-tty --passphrase q3tx65wurstbrot'; cd .."
|
||||
}
|
||||
sh "mkdir -p ../pkgarchive/"
|
||||
sh "scp ../*.deb repo@factorypackages.rz.vnc.biz:/srv/repo/apt/incoming/"
|
||||
sh "ssh repo@factorypackages.rz.vnc.biz /srv/repo/bin/import-new-packages.sh"
|
||||
sh "mv ../*.deb ../pkgarchive/"
|
||||
sh "rm ../*.dsc"
|
||||
sh "rm ../*amd64.build"
|
||||
sh "rm ../*amd64.changes"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
emailext (
|
||||
to: 'stefan.saenger@vnc.biz',
|
||||
subject: "${env.JOB_NAME} #${env.BUILD_NUMBER}",
|
||||
body: "Build URL: ${env.BUILD_URL}.",
|
||||
attachLog: false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
# vnc-hybridauth2 (vnctalk-hybrid-authenticator2)
|
||||
|
||||
Hybrid authenticator for VNCtalk / VNCmail. An Express service that sits between the
|
||||
auth-proxy's `hybridAuthURL` and the directory backends: it authenticates users against
|
||||
**LDAP** and the **VNCdirectory** PostgreSQL DB, and issues/verifies the XMPP JWT
|
||||
(`xmppToken`) that Prosody and the mail/talk APIs share for SSO.
|
||||
|
||||
Prosody's `mod_auth_http_async` points `hybridaAuthUrl` at this service's HTTP-basic
|
||||
endpoint (default port `9544`).
|
||||
|
||||
## Build & image
|
||||
|
||||
Built by Gitea Actions (`.gitea/workflows/deploy.yml`) on every push to `master`, using
|
||||
kaniko (no Docker daemon on the runner). The image is pushed to the Gitea registry:
|
||||
|
||||
- `gitea.saas.vnc.biz/vnclagoon/vnc-hybridauth-api:latest`
|
||||
- `gitea.saas.vnc.biz/vnclagoon/vnc-hybridauth-api:sha-<short-sha>`
|
||||
|
||||
Registry auth uses the `REGISTRY_USER` / `REGISTRY_TOKEN` Actions secrets. The image runs
|
||||
as the non-root `vncuser` (uid 1001) and starts `node /usr/share/vnctalk-hybrid-authenticator2/app/app.js`.
|
||||
|
||||
## Configuration
|
||||
|
||||
`config.js` (copied into the image as `config/vnc-hybrid-authenticator.js`) is env-driven;
|
||||
the `development` profile reads `NODE_ENV`-scoped values from `process.env` (LDAP URI/bind,
|
||||
Postgres host/port/name/user/pass, `xmppToken`, `domain`). Provide them via the deployment
|
||||
(ArgoCD in the `vnc-iac-env` GitOps repo), sourced from Infisical — do **not** commit
|
||||
secrets to this repo.
|
||||
|
||||
## Deploy
|
||||
|
||||
Deployed by the ArgoCD application in `vnc-iac-env` (the hybrid-auth service that Prosody
|
||||
and the mail/talk APIs call). This repo has no live deploy manifest; the image tag is pinned
|
||||
in that GitOps repo.
|
||||
|
||||
## Legacy removed
|
||||
|
||||
The GitLab CI (`.gitlab-ci.yml`), `Jenkinsfile.deprecated`, and the GCP dev bootstrap
|
||||
(`startgcpdevapi.sh`) were removed during the GitLab → Gitea migration. The old
|
||||
`eu.gcr.io/vnc-development/vnc-hybridauth-api` promotion flow (`prod-*` / `stable-*` tags)
|
||||
is not carried over; the current build pushes a single `master` → `sha-*` + `latest`.
|
||||
+387
-47
@@ -5,7 +5,7 @@ var jwt = require('jsonwebtoken');
|
||||
var express = require('express');
|
||||
require('express-async-errors');
|
||||
var bodyParser = require('body-parser');
|
||||
var request = require('request');
|
||||
var request = require('@cypress/request');
|
||||
var Pool = require('pg-pool');
|
||||
var LDAP = require('ldapjs');
|
||||
|
||||
@@ -17,45 +17,89 @@ console.log(moment().format("LTS") + ' Using configuration', config);
|
||||
|
||||
var servicePort = config.servicePort;
|
||||
|
||||
var adBaseFilter = '(&(objectClass=user)';
|
||||
|
||||
if ((config.adBaseFilter) && (config.adBaseFilter != null)) {
|
||||
adBaseFilter = config.adBaseFilter;
|
||||
}
|
||||
|
||||
var ldap;
|
||||
ldap = LDAP.createClient({
|
||||
url: config.ldap.ldapUri, // string
|
||||
// do not wait longer than 1 minute for ldap connect
|
||||
connectTimeout: 60 * 1000, // Milliseconds client should wait before timing out on TCP connections (Default: OS default)
|
||||
reconnect: {
|
||||
initialDelay: 200,
|
||||
maxDelay: 1000,
|
||||
failAfter: 10
|
||||
}
|
||||
});
|
||||
|
||||
// these options are applied in search methods
|
||||
var base = config.ldap.searchBase; // default base for all future searches
|
||||
//filter: config.ldap.filter, // default filter for all future searches
|
||||
var scope = 'sub'; // scope: LDAP.SUBTREE
|
||||
|
||||
if (!config.noLDAP) {
|
||||
if (!config.useRedmineAuth) {
|
||||
ldap = LDAP.createClient({
|
||||
url: config.ldap.ldapUri, // string
|
||||
// do not wait longer than 1 minute for ldap connect
|
||||
connectTimeout: 60 * 1000, // Milliseconds client should wait before timing out on TCP connections (Default: OS default)
|
||||
reconnect: {
|
||||
initialDelay: 200,
|
||||
maxDelay: 1000,
|
||||
failAfter: 10
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var dbpool = new Pool({
|
||||
let dbpoolOpts = {
|
||||
database: config.database.name,
|
||||
user: config.database.user,
|
||||
password: config.database.pass,
|
||||
host: config.database.host,
|
||||
port: config.database.port,
|
||||
ssl: true,
|
||||
max: 20, // set pool max size to 20
|
||||
min: 4, // set min pool size to 4
|
||||
idleTimeoutMillis: config.database.idleTimeoutMillis, // close idle clients after 1 second
|
||||
connectionTimeoutMillis: config.database.connectionTimeoutMillis, // return an error after 1 second if connection could not be established
|
||||
})
|
||||
}
|
||||
|
||||
if (!config.disableDBtls) {
|
||||
dbpoolOpts['ssl'] = { rejectUnauthorized: false };
|
||||
}
|
||||
|
||||
var dbpool = new Pool(dbpoolOpts);
|
||||
|
||||
|
||||
let projectPoolOpts = {
|
||||
database: config.vncproject.name,
|
||||
user: config.vncproject.user,
|
||||
password: config.vncproject.pass,
|
||||
host: config.vncproject.host,
|
||||
port: config.vncproject.port,
|
||||
max: 20, // set pool max size to 20
|
||||
min: 4, // set min pool size to 4
|
||||
idleTimeoutMillis: config.database.idleTimeoutMillis, // close idle clients after 1 second
|
||||
connectionTimeoutMillis: config.database.connectionTimeoutMillis, // return an error after 1 second if connection could not be established
|
||||
}
|
||||
|
||||
if (!config.disableDBtls) {
|
||||
projectPoolOpts['ssl'] = { rejectUnauthorized: false };
|
||||
}
|
||||
|
||||
|
||||
var projectPool;
|
||||
if (config.vncproject) {
|
||||
projectPool = new Pool(projectPoolOpts);
|
||||
}
|
||||
|
||||
app.use(bodyParser.json()); // for parsing application/json
|
||||
app.use(logger('dev'));
|
||||
|
||||
function IsValidLDAPUser(username) {
|
||||
return new Promise( function (resolve, reject) {
|
||||
console.log("[IsValidLDAPUser start] username: ", username);
|
||||
var uid = username.split("@")[0];
|
||||
var domain = username.split("@")[1];
|
||||
var domain = config.domain;
|
||||
var email = username;
|
||||
if (username.indexOf("@") > -1) {
|
||||
domain = username.split("@")[1];
|
||||
} else {
|
||||
email = username + "@" + domain;
|
||||
}
|
||||
var dcstring = "ou=people,dc=";
|
||||
if (domain.indexOf(".") > -1 ){
|
||||
var dcstrings = domain.split(".");
|
||||
@@ -63,23 +107,33 @@ function IsValidLDAPUser(username) {
|
||||
dcstring += dcstrings.join(",dc=");
|
||||
}
|
||||
}
|
||||
console.log("uid: ", uid);
|
||||
console.log("domain: ", domain);
|
||||
console.log("dc: ", dcstring);
|
||||
|
||||
if ((config.searchBase) && (config.searchBase != null)) {
|
||||
dcstring = config.searchBase;
|
||||
}
|
||||
|
||||
var search_options = { scope : 'sub' };
|
||||
var _filter = '(&(objectClass=inetOrgPerson)';
|
||||
if (config.ldap.ldapType === 'zimbra') {
|
||||
_filter += '(!(zimbraIsSystemResource=TRUE))(!(zimbraIsSystemAccount=TRUE))';
|
||||
_filter += '(!(objectClass=zimbraDistributionList))(!(objectClass=zimbraCalendarResource))';
|
||||
_filter += '(&(zimbraAccountStatus=active))(&(zimbraMailStatus=enabled))';
|
||||
_filter += '(|(uid=' + uid + ')(mail=' + username + ')))';
|
||||
_filter += '(|(uid=' + uid + ')(mail=' + email + ')))';
|
||||
search_options.filter = _filter;
|
||||
// search_options.attributes = ['uid', 'mail', 'givenName', 'sn', 'displayName', 'zimbraAccountStatus'];
|
||||
search_options.attributes = ['uid', 'mail', 'zimbraAccountStatus'];
|
||||
search_options.attributes = ['uid', 'mail', 'zimbraAccountStatus', 'givenName', 'sn', 'displayName', 'title', 'telephoneNumber', 'l', 'street', 'postalCode', 'co'];
|
||||
} else if (config.ldap.ldapType === 'MS-AD') {
|
||||
|
||||
_filter = adBaseFilter;
|
||||
_filter += '(|(sAMAccountName=' + uid + ')(mail=' + username + ')))';
|
||||
search_options.filter = _filter;
|
||||
search_options.attributes = ['sAMAccountName', 'mail', 'givenName', 's', 'displayName' ];
|
||||
search_options.attributes = ['sAMAccountName', 'mail', 'givenName', 'sn', 'displayName' ];
|
||||
} else {
|
||||
console.error(moment().format("LTS") + " [profile ldap] unsupported config.ldap.ldapType : '"+config.ldap.ldapType+"'");
|
||||
resolve(false);
|
||||
resolve(null);
|
||||
}
|
||||
console.log(moment().format("LTS") + ' ldap filter: ', _filter);
|
||||
ldap.bind(
|
||||
@@ -88,14 +142,14 @@ function IsValidLDAPUser(username) {
|
||||
err => {
|
||||
if (err) {
|
||||
console.error(moment().format("LTS") + " [profile ldap.bind]", err);
|
||||
resolve(false);
|
||||
resolve(null);
|
||||
} else {
|
||||
var resultEntries = [];
|
||||
console.log(moment().format("LTS") + ' [profile ldap.search] dcstring:', dcstring);
|
||||
ldap.search(dcstring, search_options, (error, searchResult) => {
|
||||
if (error) {
|
||||
console.error(moment().format("LTS") + " [profile ldap.search error] ", error);
|
||||
resolve(false);
|
||||
resolve(null);
|
||||
}
|
||||
searchResult.on('searchEntry' , e => {
|
||||
var resultEntry = {};
|
||||
@@ -112,11 +166,14 @@ function IsValidLDAPUser(username) {
|
||||
{
|
||||
console.log('[search-ldap.end] status=' + status.status + " ("+status.errorMessage+")", resultEntries.length+ " entries");
|
||||
if (resultEntries.length === 1) {
|
||||
console.log(moment().format("LTS") + " [valid LDAP user] resultEntries: ", resultEntries);
|
||||
console.log(moment().format("LTS") + " [valid LDAP user] ", username);
|
||||
resolve(true);
|
||||
ldap.unbind();
|
||||
resolve(resultEntries[0]);
|
||||
} else {
|
||||
console.log(moment().format("LTS") + " [no valid LDAP user] - sending 401");
|
||||
resolve(false);
|
||||
ldap.unbind();
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -137,6 +194,11 @@ function IsValidLDAPAuth(username, password) {
|
||||
if (dcstrings.length > 0) {
|
||||
dcstring += dcstrings.join(",dc=");
|
||||
}
|
||||
|
||||
if ((config.searchBase) && (config.searchBase != null)) {
|
||||
dcstring = config.searchBase;
|
||||
}
|
||||
|
||||
var search_options = { scope : 'sub' };
|
||||
var uiddn = "";
|
||||
if (config.ldap.ldapType === 'zimbra') {
|
||||
@@ -147,6 +209,7 @@ function IsValidLDAPAuth(username, password) {
|
||||
console.error(moment().format("LTS") + " [profile ldap] unsupported config.ldap.ldapType : '"+config.ldap.ldapType+"'");
|
||||
resolve(false);
|
||||
}
|
||||
console.log("LDAP Auth - UID DN: ", uiddn);
|
||||
ldap.bind( uiddn, password,
|
||||
err => {
|
||||
if (err) {
|
||||
@@ -162,18 +225,105 @@ function IsValidLDAPAuth(username, password) {
|
||||
});
|
||||
}
|
||||
|
||||
function getProjectApiKey(username) {
|
||||
return new Promise( function (resolve, reject) {
|
||||
var pqueryparams = [];
|
||||
pqueryparams[0] = username;
|
||||
pqueryparams[1] = "api";
|
||||
pquery = "select tokens.value AS RedmineAPIKey from tokens where tokens.action=$2 and tokens.user_id in ";
|
||||
pquery += "(select id from users where users.status=1 and id in (select user_id from email_addresses where address=$1))"
|
||||
projectPool.query(pquery, pqueryparams, function (perr, pres) {
|
||||
if (perr != null) {
|
||||
console.log("db connection error: ", perr);
|
||||
resolve(null);
|
||||
} else {
|
||||
if (pres.rowCount > 0) {
|
||||
console.log("pres: ", pres.rows);
|
||||
resolve(pres.rows[0].redmineapikey);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function IsValidRedmineUser(username) {
|
||||
return new Promise( function (resolve, reject) {
|
||||
var uid = username.split("@")[0];
|
||||
var query = ""
|
||||
var queryparams = [];
|
||||
queryparams[0] = uid;
|
||||
var query = "SELECT DISTINCT ON (uid) users.login AS uid, users.firstname AS givenName, users.lastname AS sn FROM users WHERE users.status=1 AND users.login=$1";
|
||||
queryparams[1] = "api";
|
||||
queryparams[2] = "@" + config.domain;
|
||||
|
||||
query = "SELECT users.login AS uid, users.firstname AS givenName, users.lastname AS sn, organizations.name as memberOf, organizations.active as org_active, ";
|
||||
query += " users.login||$3 as email, tokens.value AS RedmineAPIKey FROM users, tokens, organization_users, organizations ";
|
||||
query += " WHERE users.status=1 AND lower(users.login)=$1 and tokens.action=$2 and tokens.user_id=users.id and organization_users.user_id=users.id and organizations.id=organization_users.organization_id and organizations.active";
|
||||
|
||||
|
||||
// var query = "select SELECT DISTINCT ON (uid) users.login AS uid, users.firstname AS givenName, users.lastname AS sn, users.login||\'@talk.vnc.de\' AS mail FROM users WHERE users.status=1 AND users.login=$1 AND substring(users.hashed_password, 0, length(users.hashed_password)+1) = encode(digest(users.salt||encode(digest(:password, \'sha1\'), \'hex\'), \'sha1\'), \'hex\')";
|
||||
dbpool.query(query, queryparams, function (derr, dres) {
|
||||
if (derr == null) {
|
||||
if (dres.rowCount > 0) {
|
||||
resolve(true);
|
||||
/*
|
||||
console.log("isValidRedmine query: ", query);
|
||||
console.log("isValidRedmine queryparams: ", queryparams);
|
||||
console.log("isValidRedmine dres.rows: ", dres.rows);
|
||||
*/
|
||||
var redmineUser = {
|
||||
id: dres.rows[0].uid,
|
||||
firstname: dres.rows[0].givenname,
|
||||
lastname: dres.rows[0].sn,
|
||||
email: dres.rows[0].email,
|
||||
displayName: dres.rows[0].givenname + " " + dres.rows[0].sn,
|
||||
redmineapikey: dres.rows[0].redmineapikey
|
||||
}
|
||||
resolve(redmineUser);
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
} else {
|
||||
console.log("db connection error: ", derr);
|
||||
resolve(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function IsValidRedmineUser2FA(username) {
|
||||
return new Promise( function (resolve, reject) {
|
||||
var uid = username.split("@")[0];
|
||||
var query = ""
|
||||
var queryparams = [];
|
||||
queryparams[0] = uid;
|
||||
queryparams[1] = "api";
|
||||
//var query = "SELECT DISTINCT ON (uid) users.login AS uid, users.firstname AS givenname, users.lastname AS sn FROM users WHERE users.status=1 AND users.login=$1";
|
||||
var query = "SELECT users.login AS uid, users.firstname AS givenname, users.lastname AS sn, ";
|
||||
query += "users.login||\'@"+ config.domain +"\' AS email, organizations.name as memberOf, departments.name as deptName, ";
|
||||
query += "replace(trim(replace(replace(departments.enabled_product_names, \'-\', \'\'), E\'\n\', \'\')), E\' \', \',\') as features, tokens.value as redmineapikey, cast(users.tfa_enabled as TEXT) as tfa_enabled ";
|
||||
query += "FROM users JOIN organization_users ON organization_users.user_id=users.id ";
|
||||
query += "JOIN organizations ON organizations.id=organization_users.organization_id JOIN departments ON departments.id=organization_users.department_id JOIN tokens ON tokens.user_id=users.id ";
|
||||
query += "WHERE users.status=1 AND lower(users.login)=$1 AND tokens.action=$2 AND organization_users.status=1 AND organizations.active=true";
|
||||
|
||||
// var query = "select SELECT DISTINCT ON (uid) users.login AS uid, users.firstname AS givenName, users.lastname AS sn, users.login||\'@talk.vnc.de\' AS mail FROM users WHERE users.status=1 AND users.login=$1 AND substring(users.hashed_password, 0, length(users.hashed_password)+1) = encode(digest(users.salt||encode(digest(:password, \'sha1\'), \'hex\'), \'sha1\'), \'hex\')";
|
||||
dbpool.query(query, queryparams, function (derr, dres) {
|
||||
if (derr == null) {
|
||||
if (dres.rowCount > 0) {
|
||||
var redmineUser = {
|
||||
uid: dres.rows[0].uid,
|
||||
givenname: dres.rows[0].givenname,
|
||||
sn: dres.rows[0].sn,
|
||||
email: dres.rows[0].email,
|
||||
cn: dres.rows[0].givenname + " " + dres.rows[0].sn,
|
||||
memberOf: dres.rows[0].memberOf,
|
||||
features: dres.rows[0].features,
|
||||
redmineapikey: dres.rows[0].redmineapikey,
|
||||
tfa_enabled: dres.rows[0].tfa_enabled
|
||||
}
|
||||
resolve(redmineUser);
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
@@ -198,7 +348,7 @@ function IsValidRedmineAuth(username, password) {
|
||||
queryparams[3] = "hex";
|
||||
|
||||
var query = "SELECT DISTINCT ON (uid) users.login AS uid, users.firstname AS givenName, users.lastname AS sn FROM users ";
|
||||
query += "WHERE users.status=1 AND users.login=$1 AND substring(users.hashed_password, 0, length(users.hashed_password)+1) = encode(digest(users.salt||encode(digest($2, $3), $4), $3), $4)";
|
||||
query += "WHERE users.status=1 AND lower(users.login)=$1 AND substring(users.hashed_password, 0, length(users.hashed_password)+1) = encode(digest(users.salt||encode(digest($2, $3), $4), $3), $4)";
|
||||
dbpool.query(query, queryparams, function (derr, dres) {
|
||||
if (derr == null) {
|
||||
if (dres.rowCount > 0) {
|
||||
@@ -262,7 +412,6 @@ function IsValidOldSecret(username, password) {
|
||||
function IsValidJWT(username,password) {
|
||||
try {
|
||||
var xmppToken = config.xmppToken;
|
||||
console.log("decodePlain: ", jwt.decode(password));
|
||||
var decodedToken = jwt.verify(password, xmppToken);
|
||||
console.log("decodedJWT: ", decodedToken);
|
||||
return true;
|
||||
@@ -272,11 +421,21 @@ function IsValidJWT(username,password) {
|
||||
}
|
||||
}
|
||||
|
||||
function getFirstElement(elements) {
|
||||
var result;
|
||||
if (typeof(elements) == "string"){
|
||||
result = elements;
|
||||
} else if (typeof(elements) == "object") {
|
||||
result = elements[0];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
app.get('/', async function (req, res) {
|
||||
if (req.headers.authorization && req.headers.authorization.startsWith("Basic")) {
|
||||
try {
|
||||
var b64input = req.headers.authorization.split(" ")[1];
|
||||
var decodedInput = new Buffer(b64input, 'base64').toString('ascii');
|
||||
var decodedInput = Buffer.from(b64input, 'base64').toString('ascii');
|
||||
var username = decodedInput.split(":")[0];
|
||||
var passwordArray = decodedInput.split(":");
|
||||
var password = "";
|
||||
@@ -287,42 +446,100 @@ app.get('/', async function (req, res) {
|
||||
}
|
||||
}
|
||||
if (config.useRedmineAuth) {
|
||||
let validRedmineUser = await IsValidRedmineUser(username);
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - IsValidRedmineUser: ', validRedmineUser);
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - password: ', password);
|
||||
|
||||
let validRedmineUser = false;
|
||||
var finalProfile = {};
|
||||
let userProfile = await IsValidRedmineUser(username);
|
||||
|
||||
if (userProfile) {
|
||||
validRedmineUser = true;
|
||||
}
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - IsValidRedmineUser: ', validRedmineUser, userProfile);
|
||||
if (config.debug) {
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - password: ', password);
|
||||
}
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - indesxforOldToken: ', password.indexOf("-"));
|
||||
if (validRedmineUser === true) {
|
||||
let validRedmineAuth = await IsValidRedmineAuth(username, password);
|
||||
console.log("IsValidRedmineAuth: ", validRedmineAuth);
|
||||
console.log("IsValidOldSecret: ", IsValidOldSecret(username, password));
|
||||
console.log("IsValidJWT: ", IsValidJWT(username, password));
|
||||
console.log("IsValidRedmineAuth: ", validRedmineAuth);
|
||||
if (config.debug) {
|
||||
console.log("IsValidOldSecret: ", IsValidOldSecret(username, password));
|
||||
}
|
||||
console.log("IsValidJWT: ", IsValidJWT(username, password));
|
||||
if (validRedmineUser && (validRedmineAuth || IsValidOldSecret(username, password) || IsValidJWT(username, password))) {
|
||||
res.status(200).json(null);
|
||||
res.set({"WWW-Authenticate": "Basic " + username}).status(200).json(userProfile);
|
||||
} else {
|
||||
res.status(401).json(null);
|
||||
res.set({"WWW-Authenticate": "Basic " + username}).status(401).json(null);
|
||||
}
|
||||
} else {
|
||||
res.status(401).json(null);
|
||||
res.set({"WWW-Authenticate": "Basic " + username}).status(401).json(null);
|
||||
}
|
||||
|
||||
} else {
|
||||
let validLdapUser = await IsValidLDAPUser(username);
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - validInLDAP: ', validLdapUser);
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - password: ', password);
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - indesxforOldToken: ', password.indexOf("-"));
|
||||
if (validLdapUser === true) {
|
||||
let validLdapAuth = await IsValidLDAPAuth(username, password);
|
||||
if (validLdapUser && (validLdapAuth || IsValidOldSecret(username, password) || IsValidJWT(username, password))) {
|
||||
|
||||
if (config.noLDAP && config.noLDAP == true) {
|
||||
if (IsValidOldSecret(username, password) || IsValidJWT(username, password)) {
|
||||
res.status(200).json(null);
|
||||
} else {
|
||||
res.status(401).json(null);
|
||||
}
|
||||
} else {
|
||||
res.status(401).json(null);
|
||||
var finalProfile = {};
|
||||
let userProfile = await IsValidLDAPUser(username);
|
||||
let projectApiKey = await getProjectApiKey(username);
|
||||
let validLdapUser = false;
|
||||
let userLdapName = username;
|
||||
console.log("got profile: ", userProfile);
|
||||
if (userProfile) {
|
||||
validLdapUser = true;
|
||||
}
|
||||
if (userProfile.uid && (userProfile.uid != null)) {
|
||||
finalProfile["id"] = getFirstElement(userProfile.uid);
|
||||
}
|
||||
if (userProfile.givenName && (userProfile.givenName != null)) {
|
||||
finalProfile["firstname"] = getFirstElement(userProfile.uid);
|
||||
}
|
||||
if (userProfile.sn && (userProfile.sn != null)) {
|
||||
finalProfile["lastname"] = getFirstElement(userProfile.sn);
|
||||
}
|
||||
if (userProfile.email && (userProfile.email != null)) {
|
||||
finalProfile["email"] = getFirstElement(userProfile.email);
|
||||
userLdapName = getFirstElement(userProfile.email);
|
||||
console.log("using for LDAP: ", userLdapName);
|
||||
}
|
||||
if (userProfile.mail && (userProfile.mail != null)) {
|
||||
finalProfile["email"] = getFirstElement(userProfile.email);
|
||||
userLdapName = getFirstElement(userProfile.mail);
|
||||
console.log("using for LDAP: ", userLdapName);
|
||||
}
|
||||
if (userProfile.displayName && (userProfile.displayName != null)) {
|
||||
finalProfile["displayName"] = getFirstElement(userProfile.displayName);
|
||||
}
|
||||
if (projectApiKey && (projectApiKey != null)) {
|
||||
finalProfile["RedmineApiKey"] = projectApiKey;
|
||||
}
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - validInLDAP: ', validLdapUser);
|
||||
if (config.debug) {
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - password: ', password);
|
||||
}
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - indesxforOldToken: ', password.indexOf("-"));
|
||||
if (validLdapUser === true) {
|
||||
// let validLdapAuth = await IsValidLDAPAuth(username, password);
|
||||
let validLdapAuth = await IsValidLDAPAuth(userLdapName, password);
|
||||
if (validLdapUser && (validLdapAuth || IsValidOldSecret(username, password) || IsValidJWT(username, password))) {
|
||||
// if (IsValidOldSecret(username, password) || IsValidJWT(username, password)) {
|
||||
|
||||
res.status(200).json(finalProfile);
|
||||
} else {
|
||||
res.status(401).json(null);
|
||||
}
|
||||
} else {
|
||||
res.status(401).json(null);
|
||||
}
|
||||
// res.status(200).json(null);
|
||||
}
|
||||
}
|
||||
|
||||
// res.status(200).json(null);
|
||||
} catch (e) {
|
||||
console.log(moment().format("LTS") + ' Error: ', e);
|
||||
}
|
||||
@@ -333,10 +550,133 @@ app.get('/', async function (req, res) {
|
||||
|
||||
});
|
||||
|
||||
app.get('/login2fa', async function (req, res) {
|
||||
if (req.headers.authorization && req.headers.authorization.startsWith("Basic")) {
|
||||
try {
|
||||
var b64input = req.headers.authorization.split(" ")[1];
|
||||
var decodedInput = Buffer.from(b64input, 'base64').toString('ascii');
|
||||
var username = decodedInput.split(":")[0];
|
||||
var passwordArray = decodedInput.split(":");
|
||||
var password = "";
|
||||
for (var i = 1; i < passwordArray.length; i++) {
|
||||
password += passwordArray[i];
|
||||
if (i < passwordArray.length - 1) {
|
||||
password += ":";
|
||||
}
|
||||
}
|
||||
if (config.useRedmineAuth) {
|
||||
let validRedmineUser = false;
|
||||
var finalProfile = {};
|
||||
let userProfile = await IsValidRedmineUser2FA(username);
|
||||
|
||||
if (userProfile) {
|
||||
validRedmineUser = true;
|
||||
}
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - IsValidRedmineUser: ', validRedmineUser);
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - userProfile: ', userProfile);
|
||||
if (config.debug) {
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - password: ', password);
|
||||
}
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - indesxforOldToken: ', password.indexOf("-"));
|
||||
if (validRedmineUser === true) {
|
||||
let validRedmineAuth = await IsValidRedmineAuth(username, password);
|
||||
console.log("IsValidRedmineAuth: ", validRedmineAuth);
|
||||
if (config.debug) {
|
||||
console.log("IsValidOldSecret: ", IsValidOldSecret(username, password));
|
||||
}
|
||||
console.log("IsValidJWT: ", IsValidJWT(username, password));
|
||||
if (validRedmineUser && (validRedmineAuth || IsValidOldSecret(username, password) || IsValidJWT(username, password))) {
|
||||
res.set({"WWW-Authenticate": "Basic " + username}).status(200).json(userProfile);
|
||||
} else {
|
||||
res.set({"WWW-Authenticate": "Basic " + username}).status(401).json(null);
|
||||
}
|
||||
} else {
|
||||
res.status(401).json(null);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (config.noLDAP && config.noLDAP == true) {
|
||||
if (IsValidOldSecret(username, password) || IsValidJWT(username, password)) {
|
||||
res.status(200).json(null);
|
||||
} else {
|
||||
res.status(401).json(null);
|
||||
}
|
||||
} else {
|
||||
var finalProfile = {};
|
||||
let userProfile = await IsValidLDAPUser(username);
|
||||
let projectApiKey = await getProjectApiKey(username);
|
||||
let validLdapUser = false;
|
||||
let userLdapName = username;
|
||||
console.log("got profile: ", userProfile);
|
||||
if (userProfile) {
|
||||
validLdapUser = true;
|
||||
}
|
||||
if (userProfile.uid && (userProfile.uid != null)) {
|
||||
finalProfile["id"] = getFirstElement(userProfile.uid);
|
||||
}
|
||||
if (userProfile.givenName && (userProfile.givenName != null)) {
|
||||
finalProfile["firstname"] = getFirstElement(userProfile.uid);
|
||||
}
|
||||
if (userProfile.sn && (userProfile.sn != null)) {
|
||||
finalProfile["lastname"] = getFirstElement(userProfile.sn);
|
||||
}
|
||||
if (userProfile.email && (userProfile.email != null)) {
|
||||
finalProfile["email"] = getFirstElement(userProfile.email);
|
||||
userLdapName = getFirstElement(userProfile.email);
|
||||
console.log("using for LDAP: ", userLdapName);
|
||||
}
|
||||
if (userProfile.mail && (userProfile.mail != null)) {
|
||||
finalProfile["email"] = getFirstElement(userProfile.email);
|
||||
userLdapName = getFirstElement(userProfile.mail);
|
||||
console.log("using for LDAP: ", userLdapName);
|
||||
}
|
||||
if (userProfile.displayName && (userProfile.displayName != null)) {
|
||||
finalProfile["displayName"] = getFirstElement(userProfile.displayName);
|
||||
}
|
||||
if (projectApiKey && (projectApiKey != null)) {
|
||||
finalProfile["RedmineApiKey"] = projectApiKey;
|
||||
}
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - validInLDAP: ', validLdapUser);
|
||||
if (config.debug) {
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - password: ', password);
|
||||
}
|
||||
console.log(moment().format("LTS") + ' username ' + username +' - indesxforOldToken: ', password.indexOf("-"));
|
||||
if (validLdapUser === true) {
|
||||
// let validLdapAuth = await IsValidLDAPAuth(username, password);
|
||||
let validLdapAuth = await IsValidLDAPAuth(userLdapName, password);
|
||||
if (validLdapUser && (validLdapAuth || IsValidOldSecret(username, password) || IsValidJWT(username, password))) {
|
||||
// if (IsValidOldSecret(username, password) || IsValidJWT(username, password)) {
|
||||
|
||||
res.status(200).json(finalProfile);
|
||||
} else {
|
||||
res.status(401).json(null);
|
||||
}
|
||||
} else {
|
||||
res.status(401).json(null);
|
||||
}
|
||||
// res.status(200).json(null);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.log(moment().format("LTS") + ' Error: ', e);
|
||||
}
|
||||
} else {
|
||||
console.log(moment().format("LTS") + ' no auth header');
|
||||
res.set({"WWW-Authenticate": "Basic vnclagoon"}).status(401).json(null);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
app.get('/health', async function (req, res) {
|
||||
console.log(moment().format("LTS") + ' health check called');
|
||||
res.status(200).json(null);
|
||||
});
|
||||
|
||||
var server = app.listen(servicePort, function () {
|
||||
var host = server.address().address;
|
||||
var port = server.address().port;
|
||||
console.log(moment().format("LTS") + ' Service endpoint is http://%s:%s/', host, port);
|
||||
console.log(moment().format("LTS") + ' Service endpoint is http://%s:%s/notify', host, port);
|
||||
console.log(moment().format("LTS") + ' config', config);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
module.exports = {
|
||||
development: {
|
||||
servicePort: 9544,
|
||||
disableDBtls: process.env.disableDBtls || false,
|
||||
domain: process.env.domain || 'dev.vnc.de',
|
||||
xmppToken: process.env.xmppToken || 'xah6niighohshieKahtah',
|
||||
useRedmineAuth: true,
|
||||
ldap: {
|
||||
ldapUri: process.env.ldapUri || 'none',
|
||||
bindDn: process.env.bindDn || 'uid=zimbra,cn=admins,cn=zimbra',
|
||||
bindPassword: process.env.bindPassword || 'none',
|
||||
searchBase: process.env.searchBase || 'none',
|
||||
filter: process.env.filter || '(objectClass=inetOrgPerson)',
|
||||
config: 100,
|
||||
// valid ldapType for now: MS-AD, zimbra
|
||||
ldapType: process.env.ldapType || 'zimbra'
|
||||
},
|
||||
database: {
|
||||
host: process.env.databaseHost || "127.0.0.1",
|
||||
port: process.env.databasePort || 54322,
|
||||
name: process.env.databaseName || "redmine",
|
||||
user: process.env.databaseUser || "redmine",
|
||||
pass: process.env.databasePass || "redmine",
|
||||
idleTimeoutMillis: 10000,
|
||||
connectionTimeoutMillis: 10000
|
||||
},
|
||||
vncproject: {
|
||||
host: process.env.redmineDbHost || "127.0.0.1",
|
||||
port: process.env.redmineDbPort || 54322,
|
||||
name: process.env.redmineDbName || "redmine",
|
||||
user: process.env.redmineDbUser || "redmine",
|
||||
pass: process.env.redmineDbPass || "redmine",
|
||||
idleTimeoutMillis: 10000,
|
||||
connectionTimeoutMillis: 10000
|
||||
}
|
||||
},
|
||||
gr13: {
|
||||
servicePort: 9544,
|
||||
xmppToken: process.env.xmppToken || 'ocu8saithoYa2teeb2ahTh9fee4is7ai',
|
||||
ldap: {
|
||||
ldapUri: process.env.ldapUri || 'ldap://192.168.21.142:389',
|
||||
bindDn: process.env.bindDn || 'uid=zimbra,cn=admins,cn=zimbra',
|
||||
bindPassword: process.env.bindPassword || 'jSVNIcRSRR',
|
||||
searchBase: process.env.searchBase || 'ou=people,dc=dev,dc=local,dc=gr13,dc=net',
|
||||
filter: process.env.filter || '(objectClass=inetOrgPerson)',
|
||||
config: 100,
|
||||
// valid ldapType for now: MS-AD, zimbra
|
||||
ldapType: process.env.ldapType || 'zimbra'
|
||||
},
|
||||
database : {
|
||||
host: process.env.prosodyDbHost || "192.168.21.143",
|
||||
port: process.env.prosodyDbPort || 5432,
|
||||
name: process.env.prosodyDbName || "prosody",
|
||||
user: process.env.prosodyDbUser || "prosody",
|
||||
pass: process.env.prosodyDbPass || "vahG7ooli7thee0iek4Ewoo9Sai6oWah",
|
||||
idleTimeoutMillis: 10000,
|
||||
connectionTimeoutMillis: 10000
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -1,62 +1,42 @@
|
||||
module.exports = {
|
||||
development: {
|
||||
servicePort: 9544,
|
||||
xmppToken: 'oothoudaeraighahkabahphisaiwaeko',
|
||||
domain: 'dev.vnc.de',
|
||||
xmppToken: 'xah6niighohshieKahtah',
|
||||
useRedmineAuth: true,
|
||||
disableDBtls: false,
|
||||
ldap: {
|
||||
ldapUri: 'ldap://zimbra.uxf.zimbra-vnc.de:389',
|
||||
ldapUri: 'none',
|
||||
bindDn: 'uid=zimbra,cn=admins,cn=zimbra',
|
||||
bindPassword: 'cfQ9f0KNR',
|
||||
searchBase: 'ou=people,dc=uxf,dc=zimbra-vnc,dc=de',
|
||||
bindPassword: 'none',
|
||||
searchBase: 'none',
|
||||
filter: '(objectClass=inetOrgPerson)',
|
||||
config: 100,
|
||||
// valid ldapType for now: MS-AD, zimbra
|
||||
ldapType: 'zimbra'
|
||||
},
|
||||
database: {
|
||||
host: "talk.uxf.zimbra-vnc.de",
|
||||
port: 5432,
|
||||
name: "prosody",
|
||||
user: "prosody",
|
||||
pass: "oolehohqueithaipeikahtaeshoozais",
|
||||
host: "127.0.0.1",
|
||||
port: 54322,
|
||||
name: "redmine",
|
||||
user: "redmine",
|
||||
pass: "redmine",
|
||||
idleTimeoutMillis: 10000,
|
||||
connectionTimeoutMillis: 10000
|
||||
},
|
||||
redminedb: {
|
||||
host: "talk.uxf.zimbra-vnc.de",
|
||||
port: 5432,
|
||||
name: "prosody",
|
||||
user: "prosody",
|
||||
pass: "oolehohqueithaipeikahtaeshoozais",
|
||||
idleTimeoutMillis: 10000,
|
||||
connectionTimeoutMillis: 10000
|
||||
}
|
||||
},
|
||||
development2: {
|
||||
xmppToken: 'irithep1KeiViemohmui3fo3eiyeitah',
|
||||
servicePort: 9544,
|
||||
ldap: {
|
||||
ldapUri: 'ldap://193.254.187.146:389',
|
||||
bindDn: 'uid=zimbra,cn=admins,cn=zimbra',
|
||||
bindPassword: 'tTBhTIWS',
|
||||
searchBase: 'ou=people,dc=dev2,dc=zimbra-vnc,dc=de',
|
||||
filter: '(objectClass=inetOrgPerson)',
|
||||
config: 100,
|
||||
// valid ldapType for now: MS-AD, zimbra
|
||||
ldapType: 'zimbra'
|
||||
},
|
||||
database: {
|
||||
host: "193.254.187.146",
|
||||
port: 5432,
|
||||
name: "prosody",
|
||||
user: "prosody",
|
||||
pass: "ooX8ieyu9uaGee6aechukoh1beePaiZoo",
|
||||
host: "127.0.0.1",
|
||||
port: 54322,
|
||||
name: "redmine",
|
||||
user: "redmine",
|
||||
pass: "redmine",
|
||||
idleTimeoutMillis: 10000,
|
||||
connectionTimeoutMillis: 10000
|
||||
}
|
||||
},
|
||||
gr13: {
|
||||
servicePort: 9544,
|
||||
xmppToken: 'ocu8saithoYa2teeb2ahTh9fee4is7ai',
|
||||
xmppToken: 'ocu8saithoYa2teeb2ahTh9fee4is7ai',
|
||||
ldap: {
|
||||
ldapUri: 'ldap://192.168.21.142:389',
|
||||
bindDn: 'uid=zimbra,cn=admins,cn=zimbra',
|
||||
|
||||
+20
-12
@@ -5,24 +5,32 @@
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "NODE_ENV=development node app/app.js",
|
||||
"start": "node app/app.js",
|
||||
"start:gr13": "NODE_ENV=gr13 node app/app.js"
|
||||
},
|
||||
"author": "VNC Software AG",
|
||||
"license": "",
|
||||
"dependencies": {
|
||||
"body-parser": "1.18.3",
|
||||
"express": "4.13.4",
|
||||
"body-parser": "1.20.3",
|
||||
"express": "4.22.1",
|
||||
"express-async-errors": "3.1.1",
|
||||
"express-basic-auth": "1.1.6",
|
||||
"express-basic-auth": "1.2.1",
|
||||
"hmacsha1": "1.0.0",
|
||||
"jsonwebtoken": "8.3.0",
|
||||
"ldapjs": "^1.0.2",
|
||||
"md5": "2.2.1",
|
||||
"moment": "2.22.2",
|
||||
"morgan": "1.8.2",
|
||||
"pg": "7.6.0",
|
||||
"pg-pool": "2.0.3",
|
||||
"request": "2.83.0"
|
||||
"jsonwebtoken": "9.0.3",
|
||||
"ldapjs": "1.0.2",
|
||||
"md5": "2.3.0",
|
||||
"moment": "2.29.4",
|
||||
"morgan": "1.10.1",
|
||||
"pg": "8.8.0",
|
||||
"pg-pool": "3.5.2",
|
||||
"@cypress/request": "3.0.10"
|
||||
},
|
||||
"resolutions": {
|
||||
"brace-expansion": "5.0.6",
|
||||
"form-data": "4.0.6",
|
||||
"lodash": "4.18.1",
|
||||
"minimatch": "10.2.4",
|
||||
"qs": "6.15.2",
|
||||
"uuid": "14.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
BROADCASTSENDER=jenkins.bot@vnc.biz
|
||||
BROADCASTID=broadcast-gel4it1o9fvi@vnc.biz
|
||||
BCTITLE=Factory - VNC Hybridauth2
|
||||
BCRECEIPIENTS=leonidas.apostolidis@vnc.biz
|
||||
BCRESTURL=https://xmpp.vnc.biz/rest
|
||||
Executable
+77
@@ -0,0 +1,77 @@
|
||||
#!/bin/bash
|
||||
|
||||
#######
|
||||
# Use Jenkins env vars if set otherwise use the gitlab-ci ones
|
||||
BUILD_URL=${BUILD_URL:-$CI_PIPELINE_URL}
|
||||
BRANCH_NAME=${BRANCH_NAME:-$CI_COMMIT_REF_NAME}
|
||||
#######
|
||||
|
||||
echo "BRANCH: $BRANCH_NAME"
|
||||
|
||||
if [ -f result.txt ]; then
|
||||
RESULT=$(cat result.txt)
|
||||
#debug
|
||||
echo "result:"
|
||||
cat result.txt
|
||||
fi
|
||||
|
||||
if [ -f code-analysis.txt ]; then
|
||||
CODEERR=$(cat code-analysis.txt)
|
||||
#debug
|
||||
echo "code-analysis"
|
||||
cat code-analysis.txt
|
||||
fi
|
||||
|
||||
AUTHOR=$(git log -1 | grep "^Author: " | awk -F "Author:" '{print $2}' | awk -F "<" '{print $1}')
|
||||
|
||||
echo "All local branches:"; git branch
|
||||
echo "BRANCH_NAME: $BRANCH_NAME"
|
||||
|
||||
JCHANGELOG=$(git log --pretty=format:%s origin/master..origin/$BRANCH_NAME | nl)
|
||||
|
||||
echo "changes:"
|
||||
echo "$JCHANGELOG"
|
||||
|
||||
|
||||
if [ "$RESULT" ]; then
|
||||
echo "$BUILD_URL - $RESULT"
|
||||
case $RESULT in
|
||||
SUCCESS|success)
|
||||
if [ "$BRANCH_NAME" = "master" ]; then
|
||||
echo -e "job succesfully finished: $BUILD_URL \n Changes: \n $JCHANGELOG" | ./tools/sendbroadcast.sh
|
||||
# nagzillac "room^vncmail__project@conference.vnc.biz^job succesfully finished: $BUILD_URL - new APK is available at https://basepackages.vnc.biz/apk/VNCmail-2.0.0-$BUILD_ID.apk"
|
||||
else
|
||||
echo -e "job succesfully finished: $BUILD_URL \n Changes: \n $JCHANGELOG \n Author: $AUTHOR" | ./tools/sendbroadcast.sh
|
||||
# nagzillac "room^vncmail__project@conference.vnc.biz^job succesfully finished: $BUILD_URL"
|
||||
fi
|
||||
;;
|
||||
UNSTABLE|WARNING|unstable)
|
||||
if [ "$CODEERR" ]; then
|
||||
if [ "$BRANCH_NAME" = "master" ]; then
|
||||
echo -e "job finished with warnings: $BUILD_URL \n $CODEERR \n Changes: \n $JCHANGELOG " | ./tools/sendbroadcast.sh
|
||||
# nagzillac "room^vncmail__project@conference.vnc.biz^job finished with warnings: $BUILD_URL \n $CODEERR \n new APK is available at https://basepackages.vnc.biz/apk/VNCmail-2.0.0-$BUILD_ID.apk"
|
||||
else
|
||||
echo -e "job finished with warnings: $BUILD_URL \n $CODEERR \n Changes: \n $JCHANGELOG \n Author: $AUTHOR" | ./tools/sendbroadcast.sh
|
||||
# nagzillac "room^vncmail__project@conference.vnc.biz^job finished with warnings: $BUILD_URL \n $CODEERR"
|
||||
fi
|
||||
else
|
||||
echo -e "job finished with warnings: $BUILD_URL \n Changes: \n $JCHANGELOG \n Author: $AUTHOR" | ./tools/sendbroadcast.sh
|
||||
#nagzillac "room^vncmail__project@conference.vnc.biz^job finished with warnings: $BUILD_URL"
|
||||
fi
|
||||
;;
|
||||
FAILURE)
|
||||
if [ "$CODEERR" ]; then
|
||||
CODENUM=$(wc -l code-analysis.txt | awk '{print $1}')
|
||||
echo -e "job FAILED - please check: $BUILD_URL \n code analysis found $CODENUM errors \n $CODEERR \n\n Changes: \n $JCHANGELOG \n Author: $AUTHOR" | ./tools/sendbroadcast.sh
|
||||
# nagzillac "room^vncmail__project@conference.vnc.biz^job FAILED - please check: $BUILD_URL \n code analysis found $CODENUM errors"
|
||||
else
|
||||
echo -e "job FAILED - please check: $BUILD_URL immediately \n Changes: \n $JCHANGELOG \n Author: $AUTHOR" | ./tools/sendbroadcast.sh
|
||||
# nagzillac "room^vncmail__project@conference.vnc.biz^job FAILED - please check: $BUILD_URL immediately"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo -e "job finished with ambigous result - please check: $BUILD_URL immediately \n Changes: \n $JCHANGELOG \n Author: $AUTHOR" | ./tools/sendbroadcast.sh
|
||||
# nagzillac "chat^stefan.saenger@vnc.biz^job finished with ambigous result - please check: $BUILD_URL immediately"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
BCBODY=`cat`
|
||||
|
||||
function die_err() {
|
||||
echo "$0: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
OldPWD=$(pwd)
|
||||
BaseDir=$(git rev-parse --show-toplevel)
|
||||
cd "$BaseDir" || exit 1
|
||||
|
||||
|
||||
CURLCRED="vnctalk:ohtai2Eicai4aiting7bec2am6Aih"
|
||||
|
||||
if [ -f "tools/broadcast.cfg" ]; then
|
||||
echo "found config"
|
||||
else
|
||||
cd "$OldPWD" || exit 1
|
||||
die_err "no broadcst config - bailing out"
|
||||
fi
|
||||
|
||||
RECEIPIENTS=$(cat tools/broadcast.cfg | grep "^BCRECEIPIENTS" | awk -F "=" '{print $2}' | tr ',' '\n' | awk '{print "<to>" $0 "</to>"}' | sed 's/ //g' | grep -v "<to></to>");
|
||||
BROADCASTSENDER=$(cat tools/broadcast.cfg | grep "^BROADCASTSENDER" | awk -F "=" '{print $2}');
|
||||
BROADCASTID=$(cat tools/broadcast.cfg | grep "^BROADCASTID" | awk -F "=" '{print $2}');
|
||||
BCTITLE=$(cat tools/broadcast.cfg | grep "^BCTITLE" | awk -F "=" '{print $2}');
|
||||
MSGID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
|
||||
BCRESTURL=$(cat tools/broadcast.cfg | grep "^BCRESTURL" | awk -F "=" '{print $2}');
|
||||
|
||||
echo "<message xmlns=\"jabber:client\" type=\"normal\" id=\"$MSGID\" to=\"$BROADCASTID\" from=\"$BROADCASTSENDER\">" > "/tmp/$MSGID.xml"
|
||||
echo "<body>$BCBODY</body>" >> "/tmp/$MSGID.xml"
|
||||
echo "<vncTalkBroadcast xmlns=\"xmpp:vnctalk\" title=\"$BCTITLE\">" >> "/tmp/$MSGID.xml"
|
||||
echo "$RECEIPIENTS" >> "/tmp/$MSGID.xml"
|
||||
echo " </vncTalkBroadcast>
|
||||
</message>" >> "/tmp/$MSGID.xml"
|
||||
|
||||
echo "raw message:"
|
||||
cat "/tmp/$MSGID.xml"
|
||||
|
||||
curl -u "$CURLCRED" -H "Content-Type: text/xml" -X POST --data-binary "@/tmp/$MSGID.xml" "$BCRESTURL"
|
||||
Reference in New Issue
Block a user