Files
MosisService/docs/DEV_PORTAL_M01_APP_PACKAGE.md

10 KiB

Milestone 1: App Package Format

Status: Decided Goal: Define how apps are bundled, signed, and validated.

Decision

Signed ZIP (Option C) with JAR/APK-style signing using Ed25519:

Format:       ZIP archive with .mosis extension
Signing:      Ed25519 (crypto/ed25519 stdlib)
Manifest:     META-INF/MANIFEST.MF with SHA-256 hashes
Validation:   Go package (mosis-portal/pkg/package)

Rationale

  1. Standard tooling - ZIP format works with all archive tools
  2. Proven approach - JAR/APK signing is battle-tested
  3. Ed25519 - Fast, secure, small signatures (64 bytes)
  4. Go stdlib - crypto/ed25519 and archive/zip in standard library
  5. Easy inspection - Developers can unzip and view contents

Package Structure

com.developer.appname-1.0.0.mosis  (ZIP archive)
├── manifest.json           # App metadata (JSON)
├── META-INF/
│   ├── MANIFEST.MF         # SHA-256 hashes of all files
│   └── CERT.SIG            # Ed25519 signature of MANIFEST.MF
├── icons/
│   ├── icon-32.png
│   ├── icon-64.png
│   └── icon-128.png
└── assets/
    ├── main.rml            # Entry point
    ├── styles/
    │   └── theme.rcss
    └── scripts/
        └── app.lua

Overview

The app package format is the foundation of the entire ecosystem. Every tool (CLI, portal, device) needs to understand this format.


Questions to Answer

  1. What files comprise an app package?
  2. How is the manifest structured?
  3. How are apps signed for integrity?
  4. How are updates handled (full vs delta)?
  5. What metadata is required (name, version, permissions, icons)?

Package Format Options

Option A: ZIP Archive

myapp.zip
├── manifest.json
├── icon.png
└── assets/
    ├── main.rml
    ├── styles.rcss
    └── app.lua
Pros Cons
Simple, standard tooling No built-in signing
Easy to inspect No metadata in filename
Wide compatibility Need separate signature file

Option B: Custom Format (.mosis)

myapp.mosis (binary format)
┌─────────────────────────┐
│ Magic bytes (4)         │
│ Version (2)             │
│ Manifest length (4)     │
│ Manifest JSON           │
│ Signature (256)         │
│ Compressed payload      │
└─────────────────────────┘
Pros Cons
Signature built-in Custom tooling needed
Efficient metadata access Harder to inspect
Single file More complex implementation
myapp.mosis/  (actually a ZIP)
├── manifest.json
├── META-INF/
│   ├── MANIFEST.MF      # File hashes
│   └── SIGNATURE.SF     # Signed manifest
├── icon.png
└── assets/
    └── ...
Pros Cons
Standard ZIP tooling Slightly more complex
JAR/APK-style signing
Easy inspection
Proven approach

Proposed Structure

com.developer.appname-1.0.0.mosis
├── manifest.json           # App metadata
├── META-INF/
│   ├── CERT.PEM            # Developer certificate
│   ├── CERT.SIG            # Signature of MANIFEST.MF
│   └── MANIFEST.MF         # SHA-256 hashes of all files
├── icons/
│   ├── icon-32.png
│   ├── icon-64.png
│   └── icon-128.png
├── assets/
│   ├── main.rml            # Entry point
│   ├── screens/
│   │   ├── home.rml
│   │   └── settings.rml
│   ├── styles/
│   │   └── theme.rcss
│   └── scripts/
│       ├── main.lua
│       └── utils.lua
└── locales/                # Optional i18n
    ├── en.json
    └── es.json

Manifest Schema

Required Fields

{
  "$schema": "https://mosis.dev/schemas/manifest-v1.json",
  "id": "com.developer.appname",
  "name": "My App",
  "version": "1.0.0",
  "version_code": 1,
  "entry": "assets/main.rml",
  "min_mosis_version": "1.0.0"
}

Full Schema

{
  "$schema": "https://mosis.dev/schemas/manifest-v1.json",

  "id": "com.developer.appname",
  "name": "My App",
  "version": "1.0.0",
  "version_code": 1,

  "description": "A short description of the app",
  "entry": "assets/main.rml",

  "author": {
    "name": "Developer Name",
    "email": "dev@example.com",
    "url": "https://developer.com"
  },

  "permissions": [
    "storage",
    "network",
    "camera"
  ],

  "icons": {
    "32": "icons/icon-32.png",
    "64": "icons/icon-64.png",
    "128": "icons/icon-128.png"
  },

  "min_mosis_version": "1.0.0",
  "target_mosis_version": "1.2.0",

  "category": "utilities",
  "tags": ["productivity", "tools"],

  "orientation": "portrait",
  "background_color": "#FFFFFF",

  "locales": ["en", "es", "fr"],
  "default_locale": "en"
}

Field Definitions

Field Type Required Description
id string Yes Unique package identifier (reverse domain)
name string Yes Display name (max 30 chars)
version string Yes Semantic version (X.Y.Z)
version_code integer Yes Incremental build number
entry string Yes Path to entry RML file
min_mosis_version string Yes Minimum Mosis version required
description string No Short description (max 80 chars)
author object No Author information
permissions array No Required permissions
icons object No Icon paths by size
category string No App store category
tags array No Searchable tags
orientation string No portrait, landscape, any
background_color string No Hex color for loading
locales array No Supported locales

Signing Mechanism

Algorithm

  • Key type: Ed25519 (fast, secure, small signatures)
  • Hash: SHA-256 for file manifests
  • Format: PEM for keys, base64 for signatures

MANIFEST.MF Format

Manifest-Version: 1.0
Created-By: mosis-cli 1.0.0

Name: manifest.json
SHA-256-Digest: base64encodedHash==

Name: assets/main.rml
SHA-256-Digest: base64encodedHash==

Name: assets/scripts/main.lua
SHA-256-Digest: base64encodedHash==

Signing Flow

1. Generate MANIFEST.MF with SHA-256 of each file
2. Sign MANIFEST.MF with developer's Ed25519 private key
3. Store signature in META-INF/CERT.SIG
4. Include developer's public key in META-INF/CERT.PEM

Verification Flow

1. Extract META-INF/MANIFEST.MF
2. Verify signature using CERT.PEM
3. Verify CERT.PEM is registered with developer account
4. Verify each file hash matches MANIFEST.MF

Size Limits

Limit Value Rationale
Max package size 50 MB Reasonable for mobile
Max individual file 10 MB Prevent abuse
Max files count 1000 Prevent zip bombs
Max path length 256 chars Filesystem compat
Max manifest size 64 KB Prevent abuse

Validation Rules

Manifest Validation

  • Valid JSON
  • All required fields present
  • id matches reverse domain pattern: ^[a-z][a-z0-9]*(\.[a-z][a-z0-9]*)+$
  • version matches semver pattern
  • version_code is positive integer
  • entry file exists in package
  • All permissions are valid permission names
  • All icons paths exist and are valid images

Package Validation

  • Valid ZIP format
  • manifest.json at root
  • No path traversal (../)
  • No absolute paths
  • No symlinks
  • Under size limits
  • No duplicate files
  • Valid file extensions only

Signature Validation

  • MANIFEST.MF present
  • CERT.SIG present
  • CERT.PEM present
  • Signature valid for MANIFEST.MF
  • All file hashes match
  • Certificate registered with developer account (for store)

File Extension Rules

Allowed Extensions

Category Extensions
UI .rml
Styles .rcss
Scripts .lua
Images .png, .jpg, .jpeg, .tga, .webp
Fonts .ttf, .otf
Data .json
Localization .json (in locales/)
Audio .ogg, .wav, .mp3

Forbidden

  • Executables: .exe, .dll, .so, .dylib
  • Scripts: .sh, .bat, .ps1, .py, .js
  • Archives: .zip, .tar, .gz (nested)

Update Handling

Full Update

  • Download complete new package
  • Verify signature
  • Atomic replacement of app directory
  • Preserve user data in separate location

Delta Updates (Future)

  • bsdiff-style patches
  • Reduces bandwidth for minor updates
  • More complex implementation
  • Consider for v2

Deliverables

  • Package format decided (Signed ZIP with .mosis extension)
  • Signing algorithm decided (Ed25519)
  • JSON Schema for manifest validation
  • Go package: pkg/package/manifest.go (parsing/validation)
  • Go package: pkg/package/validator.go (package validation)
  • Go package: pkg/package/signer.go (Ed25519 signing/verification)
  • Integration with mosis-cli build and sign commands

Test Cases

Test Description
ValidPackage Accept well-formed package
InvalidManifest Reject malformed JSON
MissingRequired Reject missing required fields
BadSignature Reject invalid signature
TamperedFile Reject if file hash mismatch
PathTraversal Reject ../ in paths
OversizePackage Reject over size limit
BadExtension Reject forbidden file types
DuplicateFiles Reject duplicate entries

Open Questions

  1. Should we support multiple entry points (e.g., widget vs full app)? → Single entry point for v1
  2. Should icons be required or have defaults? → Required (32, 64, 128 sizes)
  3. Delta updates in v1 or defer to v2? → Defer to v2 (full updates only)
  4. Support for app bundles (multiple apps in one package)? → No, one app per package

References