diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 824c770..01f58f2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest env: DOCKER_REPO: sippylabs/webrtc_phone - PLATFORMS: linux/amd64 #,linux/i386,linux/arm/v7,linux/arm64 + PLATFORMS: linux/amd64,linux/i386,linux/arm/v7,linux/arm64 BASE_IMAGE: sippylabs/rtpproxy:RFC5245_ICE steps: - name: Checkout repository @@ -31,6 +31,22 @@ jobs: with: submodules: 'recursive' + - name: Checkout SIP.js repo + uses: actions/checkout@v4 + with: + repository: 'onsip/SIP.js' + path: docker/SIP.js + + - name: Checkout Sippy B2BUA repo + uses: actions/checkout@v4 + with: + repository: 'sippy/b2bua' + path: docker/b2bua + ref: RFC7118 + + - name: Build SIP.js + run: sh -x build/SIP.js.sh + - name: Set up QEMU id: qemu uses: docker/setup-qemu-action@v3 @@ -71,3 +87,10 @@ jobs: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} platforms: ${{ env.PLATFORMS }} + + - name: Update DockerHub repo description + if: true || ${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }} + env: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + run: sh -x docker/update_description.sh README.md diff --git a/Dockerfile b/Dockerfile index 08ad653..3ae24d9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ USER root ENV DEBIAN_FRONTEND=noninteractive WORKDIR /webrtc_phone -COPY . /webrtc_phone/ +COPY docker /webrtc_phone/ # Build & install everything RUN /webrtc_phone/build.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..785d99e --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +[![Build Docker image](https://github.com/sippy/webrtc_phone/actions/workflows/build.yml/badge.svg)](https://github.com/sippy/webrtc_phone/actions/workflows/build.yml) + +# What is it? + +This is a technology demo integrating Sippy RTPProxy and Sippy B2BUA with +WebRTC-compatible clients. It includes four main components: + +1. Sippy B2BUA. +2. Sippy RTPProxy. +3. SIP.js demo application. +4. Web server. + +The container starts RTPProxy and B2BUA listening on WSS port `9876/TCP`, and +a web server on HTTPS port `443/TCP`. Both share the same self-signed TLS key +generated during the container build process. This allows users to open the +demo page and connect their browser to the B2BUA over WSS. + +When the user initiates a call, the B2BUA/RTPProxy sets up two RTP sessions +(one encrypted and one plain) and initiates an outbound SIP call to the SIP +destination controlled by the `OUTBOUND_ROUTE` environment variable. + +# Usage + +```bash +docker pull sippylabs/webrtc_phone:latest +docker run -it --name webrtc_phone -P --network=host -e OUTBOUND_ROUTE="user@sip.mypbx.net;auth=foo:bar" -d sippylabs/webrtc_phone:latest +``` + +# Introspection + +The container produces various SIP/RTP/WSS logs that can be inspected using +the `docker log` command. The amount of RTP logs can be controlled by the +`RTPP_LOG_LEVEL` environment variable. Possible values are `DBUG`, `INFO`, +`WARN`, `ERR`, and `CRIT` (in decreasing order of verbosity). + +# Caveats + +- Connection to the WSS server will fail with error `1015` in Firefox. It + works in Chrome and Microsoft Edge as long as the user accepts the security + warning when opening the demo page. This is caused by the usage of the + self-signed certificate. +- Only `Demo 1` works. +- Due to the need for a range of UDP ports for RTP sessions (2,000 by default), + the usage of the `host` network is recommended. + +# Links and References + +- [RTPProxy @ GitHub](https://github.com/sippy/rtpproxy/) +- [Sippy B2BUA @ GitHub](https://github.com/sippy/b2bua/) +- [SIP.js @ GitHub](https://github.com/onsip/SIP.js/) +- [Sources for this container @ GitHub](https://github.com/sippy/webrtc_phone/) diff --git a/build.sh b/build.sh deleted file mode 100755 index 0ee9623..0000000 --- a/build.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -set -x -set -e - -apt-get -y update -qq -apt-get -y install git python-is-python3 python3-pip npm - -git clone -b RFC7118 https://github.com/sippy/b2bua -git clone https://github.com/onsip/SIP.js.git - -python3 -m pip install --break-system-packages -U -r b2bua/requirements.txt - -git -C SIP.js apply "`pwd`/patches/SIP.js.diff" -cd SIP.js/demo -npm install -npm run build-demo -cd - -npm install http-server - -openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 365 -out server.crt -config openssl.cnf - -apt-get -y remove git -apt-get -y autoremove -apt-get -y clean diff --git a/build/SIP.js.sh b/build/SIP.js.sh new file mode 100755 index 0000000..693e974 --- /dev/null +++ b/build/SIP.js.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +set -x +set -e + +apt-get -y update -qq +apt-get -y install npm + +SJDIR="docker/SIP.js" + +git -C "${SJDIR}" apply "`pwd`/patches/SIP.js.diff" +cd "docker/SIP.js/demo" +npm install +npm run build-demo +cd - + +openssl req -newkey rsa:2048 -nodes -keyout docker/server.key -x509 -days 365 \ + -out docker/server.crt -config openssl.cnf diff --git a/docker/build.sh b/docker/build.sh new file mode 100755 index 0000000..4d48d74 --- /dev/null +++ b/docker/build.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +set -x +set -e + +apt-get -y --no-install-recommends update -qq +apt-get -y --no-install-recommends install python-is-python3 python3-pip npm + +python3 -m pip install --break-system-packages -U -r b2bua/requirements.txt +npm install http-server + +apt-get -y remove git +apt-get -y autoremove +apt-get -y clean diff --git a/openssl.cnf b/docker/openssl.cnf similarity index 100% rename from openssl.cnf rename to docker/openssl.cnf diff --git a/run.sh b/docker/run.sh similarity index 100% rename from run.sh rename to docker/run.sh diff --git a/docker/update_description.sh b/docker/update_description.sh new file mode 100644 index 0000000..ea42896 --- /dev/null +++ b/docker/update_description.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +set -e + +md5sum_q() { + md5sum "${@}" | awk '{print $1}' +} + +# Get the JWT token +TOKEN="$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${DOCKER_USERNAME}'", "password": "'${DOCKER_PASSWORD}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token)" +if [ -z "${TOKEN}" -o "${TOKEN}" = "null" ] +then + echo "ERROR: Invalid or no JWT TOKEN returned!" 1>&2 + exit 1 +fi + +BCSUM1="`jq -r .nonce < /dev/null | md5sum_q`" +BCSUM2="`echo | md5sum_q`" + +API_URL="https://hub.docker.com/v2/repositories/${DOCKER_REPO}/" +OLDCSUM="`curl -s -H "Authorization: JWT ${TOKEN}" "${API_URL}" | jq -r .full_description | md5sum_q`" +NEWCSUM="`md5sum_q "${1}"`" +if [ "${OLDCSUM}" = "${NEWCSUM}" ] +then + # description is up to date already + exit 0 +fi +if [ "${OLDCSUM}" = "${BCSUM1}" -o "${OLDCSUM}" = "${BCSUM2}" ] +then + echo "ERROR: Empty description read!" 1>&2 + exit 1 +fi + +MYNAME="`basename "${0}"`" +DESCRIPTION_FILE="`mktemp -t ${MYNAME}.XXXXXXX`" +echo '{"full_description": "' > "${DESCRIPTION_FILE}" +perl -0777 -p -e 's|\n\z||' "${1}" | perl -p -e 's|\n|\\n\n|' >> "${DESCRIPTION_FILE}" +echo '"}' >> "${DESCRIPTION_FILE}" + +# Update the description on DockerHub +curl -X PATCH -H "Content-Type: application/json" -H "Authorization: JWT ${TOKEN}" -d @"${DESCRIPTION_FILE}" "${API_URL}" +rm "${DESCRIPTION_FILE}"