Explorar el Código

document iOS client setup

Add some quality of life improvements, including
- Download CA cert from web server
- Get a clean JSON response from webapi root to verify connectivity
Mike hace 5 días
padre
commit
924fc70cec
Se han modificado 9 ficheros con 168 adiciones y 76 borrados
  1. 5 4
      Makefile
  2. 20 0
      config/ssl/nginx.conf
  3. 5 0
      docker-compose.yaml
  4. 105 0
      docs/CLIENT_IOS.md
  5. 10 1
      docs/DOCKER.md
  6. 0 25
      scripts/run_dev.sh
  7. 0 34
      scripts/run_nginx.sh
  8. 1 12
      server/webapi/server.go
  9. 22 0
      server/webapi/server_test.go

+ 5 - 4
Makefile

@@ -122,15 +122,16 @@ docker-run-stop: ## Stop Open OSCAR Server docker-compose services
 
 .PHONY: run
 run: # run the server with plain socket config
-	./scripts/run_dev.sh ./config/settings.env
+	go run -v ./cmd/server -config ./config/settings.env
 
 .PHONY: run-ssl
 run-ssl: # run the server with ssl socket config
-	./scripts/run_dev.sh ./config/ssl/settings.env
+	go run -v ./cmd/server -config ./config/ssl/settings.env
 
 .PHONY: run-nginx
-run-nginx: # run nginx for SSL termination
-	NGINX_IMAGE=$(NGINX_IMAGE) CLIENT_DIR=$(CLIENT_DIR) ./scripts/run_nginx.sh ./certs/server.pem
+run-nginx: # run nginx for SSL termination in front of `make run-ssl`
+	@[ -f ./certs/server.pem ] || { echo "./certs/server.pem not found, run 'make docker-cert' first"; exit 1; }
+	OSCAR_HOST=$(OSCAR_HOST) NGINX_UPSTREAM_HOST=open-oscar-server NGINX_IMAGE=$(NGINX_IMAGE) CLIENT_DIR=$(CLIENT_DIR) docker compose up --no-deps nginx
 
 ################################################################################
 # SSL Helpers

+ 20 - 0
config/ssl/nginx.conf

@@ -82,6 +82,26 @@ http {
             gzip_vary       on;
         }
 
+        # client trust material: the root CA and the AIM 6.x NSS database.
+        # The whole certs dir is mounted under /srv/certs, so only expose
+        # these paths and never the server's private key.
+        location = /certs/ca.crt {
+            root      /srv;
+        }
+
+        location = /certs/nss {
+            return 301 /certs/nss/;
+        }
+
+        location ^~ /certs/nss/ {
+            root      /srv;
+            autoindex on;
+        }
+
+        location ^~ /certs/ {
+            return 404;
+        }
+
         # route remaining traffic to the backend selected by $backend
         location / {
             proxy_pass http://$backend;

+ 5 - 0
docker-compose.yaml

@@ -63,6 +63,10 @@ services:
     # must exist first.
     depends_on:
       - open-oscar-server
+    # `make run-nginx` sets NGINX_UPSTREAM_HOST=open-oscar-server to send
+    # upstream traffic to a server running on the host instead.
+    extra_hosts:
+      - "${NGINX_UPSTREAM_HOST:-host.docker.internal}:host-gateway"
     ports:
       - "80:80"
       - "443:443"
@@ -71,3 +75,4 @@ services:
       - ./config/ssl/nginx.conf:/etc/nginx/nginx.conf:ro
       - ./certs:/etc/nginx/certs:ro
       - ${CLIENT_DIR:-./clients}:/srv/client:ro
+      - ./certs:/srv/certs:ro

+ 105 - 0
docs/CLIENT_IOS.md

@@ -0,0 +1,105 @@
+# AIM for iOS Client Setup
+
+This guide explains how to connect the AIM for iOS client (v5.1.3) to Open OSCAR Server. The client talks to the
+server's Web API, so setup consists of pointing the app's server URLs at your Open OSCAR Server instance and installing
+the modified app on your device.
+
+<p align="center">
+   <img width="320" alt="AIM for iOS Screenshot" src="https://github.com/user-attachments/assets/8b410e0e-060f-4626-bda9-e210f4a6548a" />
+</p>
+
+## Prerequisites
+
+1. **Compatible iOS Device**
+
+   AIM v5.1.3 is a 32-bit app, so it requires a device running iOS 5 through 10. iOS 11 and later do not run 32-bit
+   apps.
+
+2. **Ability to Sideload Apps**
+
+   Your device must be jailbroken, with a package such as AppSync Unified installed so that it can run a modified,
+   unsigned app. You also need to know how to modify an IPA file and install it onto your device.
+
+3. **Open OSCAR Server Instance**
+
+   Configure and run an Open OSCAR Server instance using one of the available guides.
+
+    - For a simple **unencrypted** installation, follow the release setup guide for your operating system.
+        - [Windows](./WINDOWS.md)
+        - [Linux](./LINUX.md)
+        - [macOS (Intel & Apple Silicon)](./MACOS.md)
+    - For an advanced **SSL-enabled** installation, follow the [Docker Setup Guide](./DOCKER.md).
+
+   The Web API must be enabled (`WEBAPI_ENABLED=true`, the default), and your device must be able to reach the server
+   over the network.
+
+## Setup Procedure
+
+1. **Acquire the AIM IPA**
+
+   Download AIM v5.1.3 from [archive.org](https://archive.org) by searching for `AOL Instant Messenger iOS`.
+
+2. **Configure Server URLs**
+
+   Modify the following production parameters in the IPA's `aim_servers.plist` file, replacing `{BASE}` with your
+   server's base URL:
+
+    - **Unencrypted:** `http://<server-ip>:8081/`, where `<server-ip>` is the LAN IP address or hostname of the
+      machine running Open OSCAR Server, and `8081` is the default Web API port (`WEBAPI_LISTENERS`). Do not use
+      `127.0.0.1`, which refers to the device itself.
+    - **SSL-enabled:** `https://<OSCAR_HOST>/`, where `<OSCAR_HOST>` is the hostname you passed to
+      `make docker-run` (e.g., `ras.dev`). The device must be able to resolve this hostname, either through DNS or its
+      hosts file.
+
+   <div align="center"><br>
+
+   | Param                      | Value                                     |
+   |----------------------------|-------------------------------------------|
+   | `api_base_url`             | `{BASE}`                                  |
+   | `api_secure_base_url`      | `{BASE}`                                  |
+   | `auth_base_url`            | `{BASE}`                                  |
+   | `sns_auth_url`             | `{BASE}_cqr/login/login.psp`              |
+   | `lifestream_settings_url`  | `{BASE}lifestream/settings`               |
+   | `lifestream_photo_api_url` | `{BASE}lifestream/`                       |
+   | `registration_api_url`     | `{BASE}rsp-websvc-3.0/reg/`               |
+   | `services_settings_url`    | `{BASE}.settings/mobile/accounts`         |
+   | `social_notification_url`  | `{BASE}.settings/mobile/notifications`    |
+
+   </div>
+
+   For example, an unencrypted server at `192.168.1.10:8081` gives `sns_auth_url` the value
+   `http://192.168.1.10:8081/_cqr/login/login.psp`.
+
+3. **Install the IPA**
+
+   Install the modified IPA onto your device.
+
+4. **Install the Root CA Certificate (SSL only)**
+
+   If you're running an SSL-enabled setup, the device must trust your server's root CA certificate.
+
+   In Safari on the device, open `http://<OSCAR_HOST>/certs/ca.crt` and install the profile when prompted.
+
+   <p align="center">
+      <img width="320" alt="iOS Certificate Installation Screenshot" src="https://github.com/user-attachments/assets/b62aeb01-4d2a-4262-a602-d772f26b94b5" />
+   </p>
+
+   On iOS 10.3 and later, you must also enable full trust for the certificate under **Settings → General → About → Certificate
+   Trust Settings**.
+
+5. **Sign In**
+
+   Open the AIM app and sign in!
+
+## Troubleshooting
+
+**The client can't connect**
+
+Open `{BASE}` in Safari on the device. If successful, you should see the following payload:
+
+```json
+{"response":{"statusCode":200,"statusText":"Ok","data":{}}}
+```
+
+If the page fails to load, the device can't reach the server: check the URL, confirm the server is running, and make
+sure the device and server are on the same network (guest Wi-Fi networks often block traffic between devices).

+ 10 - 1
docs/DOCKER.md

@@ -67,13 +67,22 @@ make docker-run OSCAR_HOST=ras.dev
 
 Replace `ras.dev` with the hostname clients will use to connect.
 
+By default, you can enter *any* screen name and password at the AIM sign-in screen to auto-create an account.
+
+> Account auto-creation is meant to be a convenience feature for local development. In a production deployment, you
+should set `DISABLE_AUTH=false` in `config/ssl/settings.env` to enforce account authentication. User accounts can be
+created via the [Management API](../README.md#-management-api).
+
 ### 6. Client Configuration
 
 #### Certificate Database
 
-Follow the [AIM 6.x client setup instructions](AIM_6_7.md#aim-6265312-setup) to install the `certs/nss/` database on each
+Follow the [AIM 6.x client setup instructions](AIM_6_7.md#aim-62-75-setup) to install the `certs/nss/` database on each
 client.
 
+To make distribution easier, nginx serves the database files at `http://<OSCAR_HOST>/certs/nss/` (e.g.,
+`http://ras.dev/certs/nss/`), so clients can download them directly from the server.
+
 #### Resolving Hostname
 
 If `OSCAR_HOST` (e.g., `ras.dev`) is not a real domain with DNS configured, you'll need to add it to each client's hosts

+ 0 - 25
scripts/run_dev.sh

@@ -1,25 +0,0 @@
-#!/bin/sh
-# This script launches Open OSCAR Server using go run with the environment vars
-# defined in config/settings.env under MacOS/Linux. The script can be run from
-# any working directory--it assumes the location of config/command files
-# relative to the path of this script.
-set -e
-
-SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
-DEFAULT_ENV_FILE="$SCRIPT_DIR/../config/settings.env"
-
-if [ "$#" -gt 1 ]; then
-  echo "Usage: $0 [path/to/settings.env]"
-  exit 1
-fi
-
-if [ "$#" -eq 1 ]; then
-  ENV_FILE="$1"
-else
-  ENV_FILE="$DEFAULT_ENV_FILE"
-fi
-REPO_ROOT="$SCRIPT_DIR/.."
-
-# Run Open OSCAR Server from repo root.
-cd "$REPO_ROOT"
-go run -v ./cmd/server -config "$ENV_FILE"

+ 0 - 34
scripts/run_nginx.sh

@@ -1,34 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ -z "$1" ]; then
-  echo "Usage: [CLIENT_DIR=/path/to/web/client] $0 /path/to/server.pem"
-  exit 1
-fi
-
-PEM_PATH="$1"
-NGINX_IMAGE="${NGINX_IMAGE:-ras-nginx:1.28.0-openssl-1.0.2u}"
-
-if [ ! -f "$PEM_PATH" ]; then
-  echo "$PEM_PATH is not a file. Run 'make docker-cert' to generate one."
-  exit 1
-fi
-
-set -- --rm -it \
-  --add-host=host.docker.internal:host-gateway \
-  --add-host=open-oscar-server:host-gateway \
-  -v "$PEM_PATH:/etc/nginx/certs/server.pem:ro" \
-  -v "$(pwd)/config/ssl/nginx.conf:/etc/nginx/nginx.conf:ro" \
-  -p 80:80 \
-  -p 443:443 \
-  -p 5193:5193
-
-# Subdirectories of CLIENT_DIR are served under /client, e.g. the directory
-# aim-client is served at /client/aim-client/.
-if [ -n "${CLIENT_DIR:-}" ]; then
-  mkdir -p "$CLIENT_DIR"
-  set -- "$@" -v "$CLIENT_DIR:/srv/client:ro"
-fi
-
-docker run "$@" "$NGINX_IMAGE"

+ 1 - 12
server/webapi/server.go

@@ -2,7 +2,6 @@ package webapi
 
 import (
 	"context"
-	"encoding/json"
 	"errors"
 	"fmt"
 	"log/slog"
@@ -353,18 +352,8 @@ type Handler struct {
 }
 
 func (h Handler) GetHelloWorldHandler(w http.ResponseWriter, r *http.Request) {
-	_, _ = fmt.Fprintf(w, "WebAPI Server Running\n")
-	// Must return the same JSON envelope as other Web AIM APIs.
 	h.Logger.Info("webapi root GET", "remote", r.RemoteAddr, "host", r.Host, "path", r.URL.Path)
-	w.Header().Set("Content-Type", "application/json; charset=utf-8")
-	resp := map[string]any{
-		"response": map[string]any{
-			"statusCode": 200,
-			"statusText": "Ok",
-			"data":       map[string]any{},
-		},
-	}
-	_ = json.NewEncoder(w).Encode(resp)
+	SendOK(w, r, nil, h.Logger)
 }
 
 // corsOptions maps the configured origin allowlist onto rs/cors.

+ 22 - 0
server/webapi/server_test.go

@@ -0,0 +1,22 @@
+package webapi
+
+import (
+	"log/slog"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+// Clients use the root URL as a connectivity check, so it must return a
+// well-formed JSON envelope.
+func TestGetHelloWorldHandlerReturnsEmptyEnvelope(t *testing.T) {
+	h := Handler{Logger: slog.Default()}
+
+	rr := httptest.NewRecorder()
+	h.GetHelloWorldHandler(rr, httptest.NewRequest(http.MethodGet, "/", nil))
+
+	assert.Equal(t, http.StatusOK, rr.Code)
+	assert.JSONEq(t, `{"response":{"statusCode":200,"statusText":"Ok","data":{}}}`, rr.Body.String())
+}