UNCLASSIFIED

Commit 3593415f authored by Michael Freeman's avatar Michael Freeman
Browse files

Merge branch 'unnamed_freeman-patch' into 'development'

Unnamed freeman patch

See merge request !41
parents e0d0d382 ad242483
Pipeline #330771 canceled with stages
in 2 minutes and 4 seconds
ARG BASE_REGISTRY=registry1.dso.mil ARG BASE_REGISTRY=registry1.dso.mil
ARG BASE_IMAGE=ironbank/opensource/nodejs/nodejs12 ARG BASE_IMAGE=ironbank/opensource/nodejs/nodejs16
ARG BASE_TAG=12.22.1 ARG BASE_TAG=16.3.0
FROM lovasoa/wbo:v1.14.3 as base FROM lovasoa/wbo:v1.14.4 as base
FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG}
USER 0 USER 0
RUN rm -rf /opt/app && \
mkdir /opt/app
COPY --from=base /opt/app /opt/app COPY --from=base /opt/app /opt/app
COPY --from=base /usr/local/lib/node_modules /usr/local/lib/node_modules
COPY scripts/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
COPY scripts/server.js /opt/app/server/server.js
# COPY statsd-client-0.4.7.tgz /opt/app
WORKDIR /opt/app WORKDIR /opt/app
RUN dnf upgrade -y && \ RUN dnf upgrade -y && \
dnf install npm -y && \ dnf install npm -y && \
# npm install statsd-client-0.4.7.tgz && \
# rm statsd-client-0.4.7.tgz && \
npm install --production && \ npm install --production && \
dnf -y remove npm && \ dnf -y remove npm && \
dnf clean all && \ dnf clean all && \
rm -rf /var/cache/dnf && \ rm -rf /var/cache/dnf && \
chown -R $USER:$(id -gn $USER) /home/node/.config chown -R node:node /opt/app && \
chmod 775 /usr/local/bin/docker-entrypoint.sh
ENV PORT 8080 USER node:node
EXPOSE 8080
USER 1001 ENV PORT=80
EXPOSE 80
VOLUME /opt/app/server-data VOLUME /opt/app/server-data
HEALTHCHECK --start-period=5s --timeout=5s \ HEALTHCHECK --start-period=5s --timeout=5s CMD curl -fs http://127.0.0.1:80/ || exit 1
CMD curl -fs http://127.0.0.1:8080/ || exit 1
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["npm", "start"] CMD ["/usr/local/bin/node", "server/server.js"]
apiVersion: v1
kind: Service
metadata:
name: wbo
spec:
selector:
app: wbo
ports:
- protocol: TCP
port: 8080
targetPort: 8080
nodePort: 32767
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wbo-deployment
labels:
app: wbo
spec:
replicas: 1
selector:
matchLabels:
app: wbo
template:
metadata:
labels:
app: wbo
spec:
containers:
- name: wbo
image: registry1.dsop.io/ironbank/opensource/lovasoa/wbo:1.14.3
ports:
- containerPort: 8080
volumeMounts:
- name: wbo-vol-storage
mountPath: /opt/app/server-data
volumes:
- name: wbo-vol-storage
persistentVolumeClaim:
claimName: wbo-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wbo-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 1Gi
...@@ -8,13 +8,13 @@ name: "opensource/lovasoa/wbo" ...@@ -8,13 +8,13 @@ name: "opensource/lovasoa/wbo"
# The most specific version should be the first tag and will be shown # The most specific version should be the first tag and will be shown
# on ironbank.dsop.io # on ironbank.dsop.io
tags: tags:
- "v1.14.3" - "v1.14.4"
- "latest" - "latest"
# Build args passed to Dockerfile ARGs # Build args passed to Dockerfile ARGs
args: args:
BASE_IMAGE: "opensource/nodejs/nodejs12" BASE_IMAGE: "opensource/nodejs/nodejs14"
BASE_TAG: "12.22.1" BASE_TAG: "14.15.3"
# Docker image labels # Docker image labels
labels: labels:
...@@ -22,23 +22,28 @@ labels: ...@@ -22,23 +22,28 @@ labels:
## Human-readable description of the software packaged in the image ## Human-readable description of the software packaged in the image
org.opencontainers.image.description: "WBO is an online collaborative whiteboard." org.opencontainers.image.description: "WBO is an online collaborative whiteboard."
## License(s) under which contained software is distributed ## License(s) under which contained software is distributed
org.opencontainers.image.licenses: "AGPL-3.19" org.opencontainers.image.licenses: "AGPL-v3.0"
## URL to find more information on the image ## URL to find more information on the image
org.opencontainers.image.url: "https://github.com/lovasoa/whitebophir" org.opencontainers.image.url: "https://github.com/lovasoa/whitebophir"
## Name of the distributing entity, organization or individual ## Name of the distributing entity, organization or individual
org.opencontainers.image.vendor: "lovasoa" org.opencontainers.image.vendor: "lovasoa"
org.opencontainers.image.version: "v1.14.3" org.opencontainers.image.version: "v1.14.4"
## Keywords to help with search (ex. "cicd,gitops,golang") ## Keywords to help with search (ex. "cicd,gitops,golang")
mil.dso.ironbank.image.keywords: "opensource" mil.dso.ironbank.image.keywords: "opensource"
## This value can be "opensource" or "commercial" ## This value can be "opensource" or "commercial"
mil.dso.ironbank.image.type: "opensource" mil.dso.ironbank.image.type: "opensource"
## Product the image belongs to for grouping multiple images ## Product the image belongs to for grouping multiple images
mil.dso.ironbank.product.name: "lovasoa/wbo" mil.dso.ironbank.product.name: "lovasoa/whitebophir"
# List of resources to make available to the offline build context # List of resources to make available to the offline build context
resources: resources:
- tag: lovasoa/wbo:v1.14.3 - tag: lovasoa/wbo:v1.14.4
url: docker://docker.io/lovasoa/wbo@sha256:a85b3972cfd27df6920008b13c70c6b6cc930bc261bfa24e04ec802cb04999ac url: docker://docker.io/lovasoa/wbo@sha256:4614b2d3399be083130987f66737dfc3513da86f1954ea10faa4415d9c614498
# - filename: statsd-client-0.4.7.tgz
# url: https://registry.npmjs.org/statsd-client/-/statsd-client-0.4.7.tgz
# validation:
# type: sha256
# value: 8816d88915b047f97d72b7fa06e0b62fb2ec6fc0e2c78092d0d013cf31285c84
# List of project maintainers # List of project maintainers
maintainers: maintainers:
......
...@@ -18,15 +18,5 @@ ...@@ -18,15 +18,5 @@
"depNameTemplate": "lovasoa/wbo", "depNameTemplate": "lovasoa/wbo",
"datasourceTemplate": "docker" "datasourceTemplate": "docker"
}, },
{
"fileMatch": [
"^hardening_manifest.yaml$"
],
"matchStrings": [
"tags:\\s+-\\s+\"(?<currentValue>.+?)\""
],
"depNameTemplate": "lovasoa/wbo",
"datasourceTemplate": "docker"
}
] ]
} }
#!/bin/sh
set -e
if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ]; then
set -- node "$@"
fi
exec "$@"
var app = require("http").createServer(handler),
sockets = require("./sockets.js"),
{log, monitorFunction} = require("./log.js"),
path = require("path"),
fs = require("fs"),
crypto = require("crypto"),
serveStatic = require("serve-static"),
createSVG = require("./createSVG.js"),
templating = require("./templating.js"),
config = require("./configuration.js"),
polyfillLibrary = require("polyfill-library"),
check_output_directory = require("./check_output_directory.js");
var MIN_NODE_VERSION = 10.0;
if (parseFloat(process.versions.node) < MIN_NODE_VERSION) {
console.warn(
"!!! You are using node " +
process.version +
", wbo requires at least " +
MIN_NODE_VERSION +
" !!!"
);
}
check_output_directory(config.HISTORY_DIR);
sockets.start(app);
app.listen(config.PORT, config.HOST);
log("server started", { port: config.PORT });
var CSP =
"default-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: wss:";
var fileserver = serveStatic(config.WEBROOT, {
maxAge: 2 * 3600 * 1000,
setHeaders: function (res) {
res.setHeader("X-UA-Compatible", "IE=Edge");
res.setHeader("Content-Security-Policy", CSP);
},
});
var errorPage = fs.readFileSync(path.join(config.WEBROOT, "error.html"));
function serveError(request, response) {
return function (err) {
log("error", { error: err && err.toString(), url: request.url });
response.writeHead(err ? 500 : 404, { "Content-Length": errorPage.length });
response.end(errorPage);
};
}
/**
* Write a request to the logs
* @param {import("http").IncomingMessage} request
*/
function logRequest(request) {
log("connection", {
ip: request.socket.remoteAddress,
original_ip:
request.headers["x-forwarded-for"] || request.headers["forwarded"],
user_agent: request.headers["user-agent"],
referer: request.headers["referer"],
language: request.headers["accept-language"],
url: request.url,
});
}
/**
* @type {import('http').RequestListener}
*/
function handler(request, response) {
try {
handleRequestAndLog(request, response);
} catch (err) {
console.trace(err);
response.writeHead(500, { "Content-Type": "text/plain" });
response.end(err.toString());
}
}
const boardTemplate = new templating.BoardTemplate(
path.join(config.WEBROOT, "board.html")
);
const indexTemplate = new templating.Template(
path.join(config.WEBROOT, "index.html")
);
/**
* Throws an error if the given board name is not allowed
* @param {string} boardName
* @throws {Error}
*/
function validateBoardName(boardName) {
if (/^[\w%\-_~()]*$/.test(boardName)) return boardName;
throw new Error("Illegal board name: " + boardName);
}
/**
* @type {import('http').RequestListener}
*/
function handleRequest(request, response) {
var parsedUrl = new URL(request.url, 'http://wbo/');
var parts = parsedUrl.pathname.split("/");
if (parts[0] === "") parts.shift();
switch (parts[0]) {
case "boards":
// "boards" refers to the root directory
if (parts.length === 1) {
// '/boards?board=...' This allows html forms to point to boards
var boardName = parsedUrl.searchParams.get("board") || "anonymous";
var headers = { Location: "boards/" + encodeURIComponent(boardName) };
response.writeHead(301, headers);
response.end();
} else if (parts.length === 2 && request.url.indexOf(".") === -1) {
validateBoardName(parts[1]);
// If there is no dot and no directory, parts[1] is the board name
boardTemplate.serve(request, response);
} else {
// Else, it's a resource
request.url = "/" + parts.slice(1).join("/");
fileserver(request, response, serveError(request, response));
}
break;
case "download":
var boardName = validateBoardName(parts[1]),
history_file = path.join(
config.HISTORY_DIR,
"board-" + boardName + ".json"
);
if (parts.length > 2 && /^[0-9A-Za-z.\-]+$/.test(parts[2])) {
history_file += "." + parts[2] + ".bak";
}
log("download", { file: history_file });
fs.readFile(history_file, function (err, data) {
if (err) return serveError(request, response)(err);
response.writeHead(200, {
"Content-Type": "application/json",
"Content-Disposition": 'attachment; filename="' + boardName + '.wbo"',
"Content-Length": data.length,
});
response.end(data);
});
break;
case "export":
case "preview":
var boardName = validateBoardName(parts[1]),
history_file = path.join(
config.HISTORY_DIR,
"board-" + boardName + ".json"
);
response.writeHead(200, {
"Content-Type": "image/svg+xml",
"Content-Security-Policy": CSP,
"Cache-Control": "public, max-age=30",
});
var t = Date.now();
createSVG
.renderBoard(history_file, response)
.then(function () {
log("preview", { board: boardName, time: Date.now() - t });
response.end();
})
.catch(function (err) {
log("error", { error: err.toString(), stack: err.stack });
response.end("<text>Sorry, an error occured</text>");
});
break;
case "random":
var name = crypto
.randomBytes(32)
.toString("base64")
.replace(/[^\w]/g, "-");
response.writeHead(307, { Location: "boards/" + name });
response.end(name);
break;
case "polyfill.js": // serve tailored polyfills
case "polyfill.min.js":
polyfillLibrary
.getPolyfillString({
uaString: request.headers["user-agent"],
minify: request.url.endsWith(".min.js"),
features: {
default: { flags: ["gated"] },
es5: { flags: ["gated"] },
es6: { flags: ["gated"] },
es7: { flags: ["gated"] },
es2017: { flags: ["gated"] },
es2018: { flags: ["gated"] },
es2019: { flags: ["gated"] },
"performance.now": { flags: ["gated"] },
},
})
.then(function (bundleString) {
response.setHeader(
"Cache-Control",
"private, max-age=172800, stale-while-revalidate=1728000"
);
response.setHeader("Vary", "User-Agent");
response.setHeader("Content-Type", "application/javascript");
response.end(bundleString);
});
break;
case "": // Index page
logRequest(request);
indexTemplate.serve(request, response);
break;
default:
fileserver(request, response, serveError(request, response));
}
}
const handleRequestAndLog = monitorFunction(handleRequest);
module.exports = app;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment