Files
RSync-Studio/Scripts/old/license-sign.swift
T
2026-10-19 14:11:01 +01:00

72 lines
2.7 KiB
Swift
Executable File

#!/usr/bin/env swift
import Foundation
import CryptoKit
struct Payload: Codable {
let licenseID: String
let customerName: String?
let customerEmail: String?
let edition: String
let installationID: String
let issuedAt: Date
let expiresAt: Date?
let maxMajorVersion: Int?
}
func base64URL(_ data: Data) -> String {
data.base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
}
let args = CommandLine.arguments
func value(_ flag: String) -> String? {
guard let index = args.firstIndex(of: flag), index + 1 < args.count else { return nil }
return args[index + 1]
}
guard let installationID = value("--installation-id"), UUID(uuidString: installationID) != nil else {
fputs("Usage: swift Scripts/license-sign.swift --installation-id UUID [--name NAME] [--email EMAIL] [--edition Professional] [--license-id ID] [--max-major 1] [--expires YYYY-MM-DD]\n", stderr)
exit(2)
}
let fm = FileManager.default
let defaultPrivate = fm.homeDirectoryForCurrentUser.appendingPathComponent("Library/Application Support/Rsync Studio Licensing/license-private-key.txt")
let privateURL = value("--private-key").map { URL(fileURLWithPath: $0) } ?? defaultPrivate
let privateText = try String(contentsOf: privateURL, encoding: .utf8).trimmingCharacters(in: .whitespacesAndNewlines)
guard let privateData = Data(base64Encoded: privateText) else { throw NSError(domain: "RsyncStudioLicensing", code: 1, userInfo: [NSLocalizedDescriptionKey: "Private key is not Base64."]) }
let privateKey = try Curve25519.Signing.PrivateKey(rawRepresentation: privateData)
var expiry: Date?
if let text = value("--expires") {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd"
formatter.timeZone = TimeZone(secondsFromGMT: 0)
guard let date = formatter.date(from: text) else {
fputs("Invalid --expires date; use YYYY-MM-DD.\n", stderr)
exit(2)
}
expiry = date
}
let payload = Payload(
licenseID: value("--license-id") ?? UUID().uuidString.lowercased(),
customerName: value("--name"),
customerEmail: value("--email"),
edition: value("--edition") ?? "Professional",
installationID: installationID.lowercased(),
issuedAt: Date(),
expiresAt: expiry,
maxMajorVersion: value("--max-major").flatMap(Int.init) ?? 1
)
let encoder = JSONEncoder()
encoder.outputFormatting = [.sortedKeys]
encoder.dateEncodingStrategy = .iso8601
let data = try encoder.encode(payload)
let signature = try privateKey.signature(for: data)
let token = "RS3.\(base64URL(data)).\(base64URL(signature))"
print(token)