Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated Docker Build & Vulnerability Patching #240

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
!yarn.lock
!docker-entrypoint.sh
!build.sh
!start.sh
!default.conf
!server/*
!client/*
**/node_modules/*
51 changes: 51 additions & 0 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Build and Push Docker Image (Daily)

on:
schedule:
- cron: "0 0 * * *" # Daily at midnight (UTC)
workflow_dispatch: # Allows manual triggering of the workflow
inputs:
trigger-build:
description: 'Trigger a manual build and push'
default: 'true'

jobs:
build_and_push_multiarch:
runs-on: ubuntu-22.04
timeout-minutes: 42 # Job will timeout after 42 minutes

steps:
# Step 1: Check out the repository code
- name: Checkout code
uses: actions/checkout@v3

# Step 2: Log in to Docker Hub using secrets
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}


# Step 3: Create and use a new builder with multi-platform support
- name: Set up Docker Buildx (Multi-Arch Builder)
uses: docker/setup-buildx-action@v3
with:
driver-opts: image=moby/buildkit:master
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7

# Step 4: Set up QEMU (for multi-platform emulation)
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7

# Step 5: Build and Push Docker Image with multi-platform support (No cache)
- name: Build and Push Docker Image (Multi-Arch)
uses: docker/build-push-action@v4
with:
context: . # Path to Dockerfile in repository
push: true # Push image after build
tags: noxcis/darkwire:terra-firma # Tag for all platforms
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7 # Platforms to build for
no-cache: true # Disable caching to force a fresh build
57 changes: 31 additions & 26 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,35 +1,40 @@
FROM node:18-bullseye-slim
# builder: Builder For Darkwore
FROM --platform=$BUILDPLATFORM node:current-alpine AS builder

USER node:node

WORKDIR /home/node

# Server environmental variables will be put into server/.env
ENV MAILGUN_API_KEY=api-key \
MAILGUN_DOMAIN=darkwire.io \
[email protected] \
ABUSE_FROM_EMAIL_ADDRESS="Darkwire <[email protected]>" \
CLIENT_DIST_DIRECTORY='client/dist/'\
ROOM_HASH_SECRET='some-uuid'\
SITE_URL=https://darkwire.io \
STORE_BACKEND=memory

# Client configuration will be put into client/.env
ENV TZ=UTC \
VITE_API_HOST=localhost \
VITE_API_PROTOCOL=http \
VITE_API_PORT=3001 \
VITE_COMMIT_SHA=some_sha \
VITE_MAX_FILE_SIZE=4
VITE_COMMIT_SHA=terra-firma

WORKDIR /opt/app
COPY . .
RUN npm install -g yarn@latest --force \
&& yarn install --flat --production --no-cache \
&& yarn build --no-cache \
&& rm -rf /opt/app/node_modules \
&& yarn cache clean \
&& yarn autoclean --force

# final: Final Darkwire Image
FROM alpine:latest

WORKDIR /opt/app

RUN apk add --no-cache nginx yarn openssl iptables
COPY --from=builder /opt/app/client/dist /opt/app/client/dist
COPY --from=builder /opt/app/server /opt/app/server
COPY package.json /opt/app/package.json
COPY default.conf /etc/nginx/http.d/
COPY start.sh /opt/app/start.sh


COPY --chown=node:node . .
RUN chmod +x /opt/app/start.sh

RUN yarn && yarn build

HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 CMD \
sh -c 'pgrep nginx > /dev/null && pgrep node > /dev/null' || exit 1

STOPSIGNAL SIGINT
EXPOSE 3001
HEALTHCHECK --interval=30s --timeout=30s --start-period=10s --retries=3 \
CMD [ "curl", "-f", "${VITE_API_PROTOCOL}://localhost:${VITE_API_PORT}", "||", "exit", "1" ]
CMD ["/opt/app/start.sh", "start" ]

ENTRYPOINT [ "docker-entrypoint.sh" ]
CMD ["yarn", "start"]
STOPSIGNAL SIGTERM
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh

api_host=$API_HOST

Expand Down
1 change: 0 additions & 1 deletion client/.env.dist → client/env.dist
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ VITE_API_HOST=localhost
VITE_API_PROTOCOL=http
VITE_API_PORT=3001
VITE_COMMIT_SHA=some_sha

# To display darkwire version
VITE_COMMIT_SHA=some_sha

Expand Down
30 changes: 14 additions & 16 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
],
"license": "MIT",
"dependencies": {
"@react-hookz/web": "^20.0.2",
"@react-hookz/web": "^20.1.0",
"@reduxjs/toolkit": "^1.9.1",
"bootstrap": "^4.6.2",
"classnames": "^2.3.2",
"jquery": "3",
"jquery": "^3.7.1",
"moment": "^2.29.4",
"nanoid": "^4.0.0",
"nanoid": "^4.0.2",
"randomcolor": "^0.6.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand All @@ -32,7 +32,7 @@
"react-tooltip": "^5.2.0",
"redux": "^4.2.0",
"redux-thunk": "^2.4.2",
"sanitize-html": "^2.7.3",
"sanitize-html": "^2.11.0",
"socket.io-client": "^4.5.4",
"tinycon": "^0.6.8"
},
Expand All @@ -45,24 +45,22 @@
"coverage": "TZ=UTC vitest --coverage --watch=false"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/jest-dom": "^6.1.6",
"@testing-library/react": "^14.1.2",
"@testing-library/user-event": "^14.4.3",
"@typescript-eslint/eslint-plugin": "^5.46.0",
"@typescript-eslint/parser": "^5.46.0",
"@vitejs/plugin-react": "^3.0.0",
"@vitest/coverage-istanbul": "^0.25.7",
"@typescript-eslint/eslint-plugin": "^6.16.0",
"@typescript-eslint/parser": "^6.16.0",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.29.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.3",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.2",
"eslint-plugin-react": "^7.31.11",
"eslint-plugin-react-hooks": "^4.6.0",
"jest-environment-jsdom-sixteen": "^1.0.3",
"jest-fetch-mock": "^3.0.3",
"prettier": "^2.0.5",
"prettier": "^3.1.1",
"sass": "^1.56.2",
"typescript": "^4.9.4",
"vitest": "^0.25.7",
"typescript": "^5.3.3",
"vitest": "^1.1.0",
"vitest-fetch-mock": "^0.2.1"
},
"browserslist": {
Expand Down
2 changes: 1 addition & 1 deletion client/public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
"background_color": "#ffffff",
"scope": "/",
"description": "Secure and encrypted web chat with Darkwire.io"
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change is unnecessary ;-)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still haven't gotten around to configure my IDE, spends time time fighting docker engine.

79 changes: 58 additions & 21 deletions client/src/components/RoomLink/index.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Copy } from 'react-feather';
import { Clipboard } from 'react-feather'; // Import Clipboard icon for the copy button
import { Tooltip } from 'react-tooltip';

const RoomLink = ({ roomId, translations }) => {
const [currentRoomId, setCurrentRoomId] = React.useState(roomId);
const [showTooltip, setShowTooltip] = React.useState(false);
const [tooltipMessage, setTooltipMessage] = React.useState('');
const mountedRef = React.useRef(true);

const roomUrl = `${window.location.origin}/${roomId}`;
const roomUrl = `${window.location.origin}/${currentRoomId}`;

React.useEffect(() => {
mountedRef.current = true;
Expand All @@ -16,8 +18,9 @@ const RoomLink = ({ roomId, translations }) => {
};
}, []);

const handleClick = async () => {
const handleCopyClick = async () => {
await navigator.clipboard.writeText(roomUrl);
setTooltipMessage(translations.copyButtonTooltip);
setShowTooltip(true);
setTimeout(() => {
if (mountedRef.current) {
Expand All @@ -26,34 +29,68 @@ const RoomLink = ({ roomId, translations }) => {
}, 2000);
};

const handleRefreshClick = () => {
window.location.href = roomUrl; // Reload the page with the current room URL
};

const handleRoomIdChange = (e) => {
setCurrentRoomId(e.target.value);
};

return (
<form>
<div className="form-group">
<div>
<form>
<div className="form-group">
<div className="input-group">
<input id="room-url" className="form-control" type="text" readOnly value={roomUrl} />
<div className="input-group-append">
<button
id="copy-room"
data-testid="copy-room-button"
className="copy-room btn btn-secondary"
type="button"
onClick={handleCopyClick}
>
<Clipboard />
</button>
</div>
{showTooltip && (
<Tooltip
anchorId="copy-room"
content={tooltipMessage}
place="top"
events={[]}
isOpen={true}
/>
)}
</div>
</div>
</form>

<div className="form-group mt-3">
<label htmlFor="current-room-id">Change Room ID</label>
<div className="input-group">
<input id="room-url" className="form-control" type="text" readOnly value={roomUrl} />
<input
id="current-room-id"
className="form-control"
type="text"
value={currentRoomId}
onChange={handleRoomIdChange}
/>
<div className="input-group-append">
<button
id="copy-room"
data-testid="copy-room-button"
className="copy-room btn btn-secondary"
id="refresh-room-id"
data-testid="refresh-room-id-button"
className="btn btn-primary" // Change button class for visibility
type="button"
onClick={handleClick}
onClick={handleRefreshClick}
>
<Copy />
Go {/* Replace icon with text */}
</button>
</div>
{showTooltip && (
<Tooltip
anchorId="copy-room"
content={translations.copyButtonTooltip}
place="top"
events={[]}
isOpen={true}
/>
)}
</div>
</div>
</form>
</div>
);
};

Expand Down
3 changes: 1 addition & 2 deletions client/src/components/Welcome/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ const Welcome = ({ roomId, translations, close }) => {
<li>Support on all modern browsers (Chrome, Firefox, Safari, Safari iOS, Android)</li>
<li>Slash commands (/nick, /me, /clear)</li>
<li>Room owners can lock the room, preventing anyone else from joining</li>
<li>Front-end rewritten in React.js and Redux</li>
<li>Send files up to 4 MB</li>
<li>Send files</li>
</ul>
<div>
You can learn more{' '}
Expand Down
2 changes: 1 addition & 1 deletion client/src/config/env.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* istanbul ignore file */
export const MAX_FILE_SIZE = import.meta.VITE_MAX_FILE_SIZE || 4;
export const MAX_FILE_SIZE = import.meta.VITE_MAX_FILE_SIZE;
export const COMMIT_SHA = import.meta.env.VITE_COMMIT_SHA;

export default import.meta.env.NODE_ENV;
1 change: 1 addition & 0 deletions client/src/stylesheets/app.sass
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ button
button.btn-link.btn-plain
padding: 0px
color: white
background-color: black
jrmi marked this conversation as resolved.
Show resolved Hide resolved
text-decoration: none
color: white
&:hover, &:focus
Expand Down
Loading