Skip to main content

OPENCODE_CLOUD_BOOTSTRAP_SH

Constant OPENCODE_CLOUD_BOOTSTRAP_SH 

Source
pub const OPENCODE_CLOUD_BOOTSTRAP_SH: &[u8] = b"#!/bin/bash\nset -euo pipefail\n\nSTATE_DIR=\"/var/lib/opencode-users\"\nSTATE_FILE=\"${STATE_DIR}/.initial-otp.json\"\nSECRET_FILE=\"${STATE_DIR}/.initial-otp.secret\"\nLOCK_FILE=\"${STATE_DIR}/.initial-otp.lock\"\nCOMPLETE_MARKER_FILE=\"${STATE_DIR}/.bootstrap-complete.json\"\nPROTECTED_USER=\"opencoder\"\nBUILTIN_USERS_FILE=\"/etc/opencode-cloud/builtin-home-users.txt\"\nFALLBACK_BUILTIN_HOME_USERS=(\"opencoder\" \"ubuntu\")\nBUILTIN_HOME_USERS=()\n\njson_ok() {\n    jq -cn \"$@\"\n}\n\njson_error() {\n    local code=\"$1\"\n    local message=\"$2\"\n    local status=\"$3\"\n    jq -cn --arg code \"${code}\" --arg message \"${message}\" --argjson status \"${status}\" \\\n        \'{ok:false,code:$code,message:$message,status:$status}\'\n}\n\nensure_state_dir() {\n    install -d -m 0700 \"${STATE_DIR}\"\n    load_builtin_home_users\n}\n\nacquire_lock() {\n    exec 9>\"${LOCK_FILE}\"\n    flock -x 9\n}\n\ngenerate_random_hex() {\n    local byte_count=\"$1\"\n    od -An -N \"${byte_count}\" -tx1 /dev/urandom | tr -d \' \\n\'\n}\n\nutc_now() {\n    date -u +\"%Y-%m-%dT%H:%M:%SZ\"\n}\n\nhash_salted_otp() {\n    local salt=\"$1\"\n    local otp=\"$2\"\n    printf \"%s\" \"${salt}:${otp}\" | sha256sum | awk \'{print $1}\'\n}\n\nstate_is_active() {\n    [ -f \"${STATE_FILE}\" ] && [ -f \"${SECRET_FILE}\" ]\n}\n\nremove_state_files() {\n    rm -f \"${STATE_FILE}\" \"${SECRET_FILE}\"\n}\n\nbootstrap_is_completed() {\n    [ -f \"${COMPLETE_MARKER_FILE}\" ]\n}\n\nmark_bootstrap_completed() {\n    local completed_at\n    completed_at=\"$(utc_now)\"\n    umask 077\n    jq -cn --arg completed_at \"${completed_at}\" --arg username \"${PROTECTED_USER}\" \\\n        \'{completed:true,completed_at:$completed_at,username:$username}\' > \"${COMPLETE_MARKER_FILE}\"\n    chmod 600 \"${COMPLETE_MARKER_FILE}\"\n}\n\nget_completed_at() {\n    jq -r \'.completed_at // empty\' \"${COMPLETE_MARKER_FILE}\" 2>/dev/null || true\n}\n\nload_builtin_home_users() {\n    BUILTIN_HOME_USERS=(\"${FALLBACK_BUILTIN_HOME_USERS[@]}\")\n\n    if [ ! -r \"${BUILTIN_USERS_FILE}\" ]; then\n        return 0\n    fi\n\n    local username\n    while IFS= read -r username; do\n        username=\"$(printf \"%s\" \"${username}\" | tr -d \'\\r\\n\')\"\n        if [ -n \"${username}\" ]; then\n            BUILTIN_HOME_USERS+=(\"${username}\")\n        fi\n    done < \"${BUILTIN_USERS_FILE}\"\n}\n\nis_builtin_home_user() {\n    local username=\"$1\"\n    local builtin\n    for builtin in \"${BUILTIN_HOME_USERS[@]}\"; do\n        if [ \"${username}\" = \"${builtin}\" ]; then\n            return 0\n        fi\n    done\n    return 1\n}\n\nhas_non_protected_user_record() {\n    # Managed user records are the canonical source of configured users.\n    # Ignore image-default users so base-image accounts do not disable IOTP.\n    shopt -s nullglob\n    local record username\n    for record in \"${STATE_DIR}\"/*.json; do\n        username=\"$(jq -r \'.username // empty\' \"${record}\" 2>/dev/null || true)\"\n        if [ -z \"${username}\" ]; then\n            continue\n        fi\n        if is_builtin_home_user \"${username}\"; then\n            continue\n        fi\n        if [ \"${username}\" != \"${PROTECTED_USER}\" ]; then\n            return 0\n        fi\n    done\n    return 1\n}\n\nhas_non_protected_system_user() {\n    # Secondary safety net for unmanaged runtime-created users with /home entries.\n    local line username home\n    while IFS= read -r line; do\n        username=\"$(cut -d: -f1 <<< \"${line}\")\"\n        home=\"$(cut -d: -f6 <<< \"${line}\")\"\n        if [[ \"${home}\" != /home/* ]]; then\n            continue\n        fi\n        if is_builtin_home_user \"${username}\"; then\n            continue\n        fi\n        return 0\n    done < <(getent passwd)\n\n    return 1\n}\n\nhas_non_protected_configured_user() {\n    has_non_protected_user_record || has_non_protected_system_user\n}\n\nread_input_json() {\n    cat\n}\n\nread_input_field() {\n    local payload=\"$1\"\n    local key=\"$2\"\n    jq -r --arg key \"${key}\" \'.[$key] // empty\' <<< \"${payload}\" 2>/dev/null || true\n}\n\nvalidate_username() {\n    local username=\"$1\"\n    if [[ ! \"${username}\" =~ ^[a-z_][a-z0-9_-]{0,31}$ ]]; then\n        return 1\n    fi\n    if [ \"${username}\" = \"${PROTECTED_USER}\" ]; then\n        return 1\n    fi\n    return 0\n}\n\npassword_meets_policy() {\n    local password=\"$1\"\n    if [ \"${#password}\" -lt 12 ]; then\n        return 1\n    fi\n\n    local classes=0\n    [[ \"${password}\" =~ [[:upper:]] ]] && classes=$((classes + 1))\n    [[ \"${password}\" =~ [[:lower:]] ]] && classes=$((classes + 1))\n    [[ \"${password}\" =~ [[:digit:]] ]] && classes=$((classes + 1))\n    [[ \"${password}\" =~ [^[:alnum:]] ]] && classes=$((classes + 1))\n\n    [ \"${classes}\" -ge 3 ]\n}\n\nverify_ubuntu_platform() {\n    local distro=\"\"\n    if [ -r /etc/os-release ]; then\n        # shellcheck disable=SC1091\n        distro=\"$(. /etc/os-release && printf \"%s\" \"${ID:-}\")\"\n    fi\n    [ \"${distro}\" = \"ubuntu\" ]\n}\n\nemit_inactive_and_cleanup() {\n    remove_state_files\n    json_ok \'{ok:true,active:false,reason:\"user_exists\"}\'\n}\n\nemit_status() {\n    local include_secret=\"$1\"\n    if has_non_protected_configured_user; then\n        emit_inactive_and_cleanup\n        return 0\n    fi\n\n    if bootstrap_is_completed; then\n        local completed_at\n        completed_at=\"$(get_completed_at)\"\n        remove_state_files\n        if [ -n \"${completed_at}\" ]; then\n            jq -cn --arg completed_at \"${completed_at}\" \\\n                \'{ok:true,active:false,reason:\"completed\",completed_at:$completed_at}\'\n        else\n            json_ok \'{ok:true,active:false,reason:\"completed\"}\'\n        fi\n        return 0\n    fi\n\n    if ! state_is_active; then\n        json_ok \'{ok:true,active:false,reason:\"not_initialized\"}\'\n        return 0\n    fi\n\n    local created_at otp\n    created_at=\"$(jq -r \'.created_at // empty\' \"${STATE_FILE}\" 2>/dev/null || true)\"\n    if [ -z \"${created_at}\" ]; then\n        remove_state_files\n        json_ok \'{ok:true,active:false,reason:\"invalid_state\"}\'\n        return 0\n    fi\n\n    if [ \"${include_secret}\" = \"1\" ]; then\n        otp=\"$(tr -d \'\\r\\n\' < \"${SECRET_FILE}\" 2>/dev/null || true)\"\n        if [ -z \"${otp}\" ]; then\n            remove_state_files\n            json_ok \'{ok:true,active:false,reason:\"invalid_secret\"}\'\n            return 0\n        fi\n        jq -cn --arg created_at \"${created_at}\" --arg otp \"${otp}\" \\\n            \'{ok:true,active:true,created_at:$created_at,otp:$otp}\'\n        return 0\n    fi\n\n    jq -cn --arg created_at \"${created_at}\" \'{ok:true,active:true,created_at:$created_at}\'\n}\n\ngenerate_fresh_otp() {\n    remove_state_files\n\n    local otp salt created_at otp_hash\n    otp=\"$(generate_random_hex 48)\"\n    salt=\"$(generate_random_hex 16)\"\n    created_at=\"$(utc_now)\"\n    otp_hash=\"$(hash_salted_otp \"${salt}\" \"${otp}\")\"\n\n    jq -cn \\\n        --arg created_at \"${created_at}\" \\\n        --arg salt \"${salt}\" \\\n        --arg otp_hash \"${otp_hash}\" \\\n        \'{version:1,active:true,created_at:$created_at,salt:$salt,otp_hash:$otp_hash}\' > \"${STATE_FILE}\"\n\n    umask 077\n    printf \"%s\" \"${otp}\" > \"${SECRET_FILE}\"\n    chmod 600 \"${STATE_FILE}\" \"${SECRET_FILE}\"\n\n    jq -cn --arg created_at \"${created_at}\" --arg otp \"${otp}\" \\\n        \'{ok:true,active:true,created_at:$created_at,otp:$otp}\'\n}\n\ncmd_init_internal() {\n    if has_non_protected_configured_user; then\n        emit_inactive_and_cleanup\n        return 0\n    fi\n\n    if bootstrap_is_completed; then\n        emit_status \"0\"\n        return 0\n    fi\n\n    if state_is_active; then\n        emit_status \"1\"\n        return 0\n    fi\n\n    generate_fresh_otp\n}\n\ncmd_init() {\n    ensure_state_dir\n    acquire_lock\n    cmd_init_internal\n}\n\ncmd_reset() {\n    ensure_state_dir\n    acquire_lock\n\n    rm -f \"${COMPLETE_MARKER_FILE}\"\n    generate_fresh_otp\n}\n\ncmd_status() {\n    local include_secret=\"0\"\n    if [ \"${1:-}\" = \"--include-secret\" ]; then\n        include_secret=\"1\"\n    fi\n\n    ensure_state_dir\n    acquire_lock\n    emit_status \"${include_secret}\"\n}\n\nverify_otp_internal() {\n    local otp=\"$1\"\n    local salt expected_hash actual_hash\n\n    if ! state_is_active; then\n        json_error \"inactive\" \"Bootstrap one-time password is not active.\" 403\n        return 0\n    fi\n\n    salt=\"$(jq -r \'.salt // empty\' \"${STATE_FILE}\" 2>/dev/null || true)\"\n    expected_hash=\"$(jq -r \'.otp_hash // empty\' \"${STATE_FILE}\" 2>/dev/null || true)\"\n    if [ -z \"${salt}\" ] || [ -z \"${expected_hash}\" ]; then\n        remove_state_files\n        json_error \"inactive\" \"Bootstrap state is invalid.\" 403\n        return 0\n    fi\n\n    actual_hash=\"$(hash_salted_otp \"${salt}\" \"${otp}\")\"\n    if [ \"${actual_hash}\" != \"${expected_hash}\" ]; then\n        json_error \"otp_invalid\" \"Initial one-time password is invalid.\" 401\n        return 0\n    fi\n\n    json_ok \'{ok:true,active:true}\'\n}\n\ncmd_verify() {\n    local payload otp\n    payload=\"$(read_input_json)\"\n    otp=\"$(read_input_field \"${payload}\" \"otp\")\"\n\n    if [ -z \"${otp}\" ]; then\n        json_error \"invalid_request\" \"Missing one-time password.\" 400\n        return 0\n    fi\n\n    ensure_state_dir\n    acquire_lock\n\n    if has_non_protected_configured_user; then\n        emit_inactive_and_cleanup\n        return 0\n    fi\n\n    verify_otp_internal \"${otp}\"\n}\n\ncmd_complete() {\n    local payload otp verify_json verify_code\n    payload=\"$(read_input_json)\"\n    otp=\"$(read_input_field \"${payload}\" \"otp\")\"\n\n    if [ -z \"${otp}\" ]; then\n        json_error \"invalid_request\" \"Missing one-time password.\" 400\n        return 0\n    fi\n\n    ensure_state_dir\n    acquire_lock\n\n    if has_non_protected_configured_user; then\n        emit_inactive_and_cleanup\n        return 0\n    fi\n\n    verify_json=\"$(verify_otp_internal \"${otp}\")\"\n    verify_code=\"$(jq -r \'.code // empty\' <<< \"${verify_json}\" 2>/dev/null || true)\"\n    if [ -n \"${verify_code}\" ]; then\n        printf \"%s\\n\" \"${verify_json}\"\n        return 0\n    fi\n\n    remove_state_files\n    mark_bootstrap_completed\n\n    jq -cn --arg username \"${PROTECTED_USER}\" \'{ok:true,completed:true,active:false,username:$username}\'\n}\n\ncmd_create_user() {\n    local payload otp username password\n    payload=\"$(read_input_json)\"\n    otp=\"$(read_input_field \"${payload}\" \"otp\")\"\n    username=\"$(read_input_field \"${payload}\" \"username\")\"\n    password=\"$(read_input_field \"${payload}\" \"password\")\"\n\n    if [ -z \"${otp}\" ] || [ -z \"${username}\" ] || [ -z \"${password}\" ]; then\n        json_error \"invalid_request\" \"otp, username, and password are required.\" 400\n        return 0\n    fi\n\n    ensure_state_dir\n    acquire_lock\n\n    if has_non_protected_configured_user; then\n        emit_inactive_and_cleanup\n        return 0\n    fi\n\n    local verify_json verify_code\n    verify_json=\"$(verify_otp_internal \"${otp}\")\"\n    verify_code=\"$(jq -r \'.code // empty\' <<< \"${verify_json}\" 2>/dev/null || true)\"\n    if [ -n \"${verify_code}\" ]; then\n        printf \"%s\\n\" \"${verify_json}\"\n        return 0\n    fi\n\n    if ! verify_ubuntu_platform; then\n        json_error \"unsupported_platform\" \"Initial signup is currently supported only on Ubuntu containers.\" 400\n        return 0\n    fi\n\n    if ! validate_username \"${username}\"; then\n        json_error \"invalid_username\" \"Username must match ^[a-z_][a-z0-9_-]{0,31}$ and cannot be reserved.\" 400\n        return 0\n    fi\n\n    if ! password_meets_policy \"${password}\"; then\n        json_error \"invalid_password\" \"Password must be at least 12 characters and include 3 of 4 classes.\" 400\n        return 0\n    fi\n\n    if id -u \"${username}\" >/dev/null 2>&1; then\n        json_error \"username_exists\" \"Username already exists.\" 409\n        return 0\n    fi\n\n    if ! useradd -m -s /bin/bash \"${username}\" >/dev/null 2>&1; then\n        json_error \"create_failed\" \"Failed to create the Linux user account.\" 500\n        return 0\n    fi\n\n    if ! printf \"%s:%s\\n\" \"${username}\" \"${password}\" | chpasswd >/dev/null 2>&1; then\n        userdel -r \"${username}\" >/dev/null 2>&1 || true\n        json_error \"create_failed\" \"Failed to set password for the new user.\" 500\n        return 0\n    fi\n\n    local shadow_hash status locked record_path\n    shadow_hash=\"$(getent shadow \"${username}\" | cut -d: -f2)\"\n    if [ -z \"${shadow_hash}\" ]; then\n        json_error \"create_failed\" \"Failed to read password hash for the new user.\" 500\n        return 0\n    fi\n\n    status=\"$(passwd -S \"${username}\" | tr -s \' \' | cut -d\' \' -f2)\"\n    locked=\"false\"\n    if [ \"${status}\" = \"L\" ]; then\n        locked=\"true\"\n    fi\n\n    record_path=\"${STATE_DIR}/${username}.json\"\n    umask 077\n    jq -cn --arg username \"${username}\" --arg hash \"${shadow_hash}\" --argjson locked \"${locked}\" \\\n        \'{username:$username,password_hash:$hash,locked:$locked}\' > \"${record_path}\"\n    chmod 600 \"${record_path}\"\n\n    remove_state_files\n    mark_bootstrap_completed\n\n    jq -cn --arg username \"${username}\" \'{ok:true,created:true,username:$username}\'\n}\n\nusage() {\n    cat <<\'EOF\'\nUsage: opencode-cloud-bootstrap <command>\n\nCommands:\n  init                 Initialize bootstrap OTP if needed\n  reset                Reset bootstrap completion and reinitialize OTP\n  status [--include-secret]\n                       Show bootstrap status\n  verify               Verify OTP (expects JSON stdin: {\"otp\":\"...\"})\n  complete             Complete bootstrap after verified OTP (expects JSON stdin: {\"otp\":\"...\"})\n  create-user          Create first user (expects JSON stdin: {\"otp\":\"...\",\"username\":\"...\",\"password\":\"...\"})\nEOF\n}\n\nmain() {\n    local command=\"${1:-}\"\n    shift || true\n\n    case \"${command}\" in\n        init)\n            cmd_init \"$@\"\n            ;;\n        reset)\n            cmd_reset \"$@\"\n            ;;\n        status)\n            cmd_status \"$@\"\n            ;;\n        verify)\n            cmd_verify \"$@\"\n            ;;\n        complete)\n            cmd_complete \"$@\"\n            ;;\n        create-user)\n            cmd_create_user \"$@\"\n            ;;\n        *)\n            usage >&2\n            exit 1\n            ;;\n    esac\n}\n\nmain \"$@\"\n";