mirror of
https://github.com/block/buzz.git
synced 2026-10-27 12:40:30 +00:00
fix(ios): support Xcode 27 with pinned secp plugin approval
Signed-off-by: Tom Brow <tomb@block.xyz>
This commit is contained in:
2
.github/workflows/_ci-clients.yml
vendored
2
.github/workflows/_ci-clients.yml
vendored
@@ -186,6 +186,8 @@ jobs:
|
||||
- name: Build
|
||||
if: matrix.lane == 'native'
|
||||
run: swift build --package-path mobile/ios/BuzzPushKit
|
||||
- name: Test pinned Swift plugin approval
|
||||
run: ruby scripts/test-swift-plugin-trust.rb
|
||||
- name: Build release
|
||||
if: matrix.lane == 'native'
|
||||
run: swift build -c release --package-path mobile/ios/BuzzPushKit
|
||||
|
||||
@@ -8,7 +8,7 @@ let package = Package(
|
||||
.library(name: "BuzzPushKit", targets: ["BuzzPushKit"])
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/21-DOT-DEV/swift-secp256k1.git", exact: "0.21.1"),
|
||||
.package(url: "https://github.com/21-DOT-DEV/swift-secp256k1.git", exact: "0.23.2"),
|
||||
.package(url: "https://github.com/swhitty/SwiftDraw.git", exact: "0.29.0")
|
||||
],
|
||||
targets: [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import CryptoKit
|
||||
import Foundation
|
||||
import ImageIO
|
||||
import P256K
|
||||
@_implementationOnly import P256K
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
/// Fetches an avatar with the extension's private HTTP cache and bounded native decoding.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import CryptoKit
|
||||
import Foundation
|
||||
import P256K
|
||||
@_implementationOnly import P256K
|
||||
|
||||
/// Account and relay identity for one local sign-in's notification cache.
|
||||
public struct BuzzNotificationCacheScope: Codable, Equatable, Sendable {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import CryptoKit
|
||||
import Foundation
|
||||
import P256K
|
||||
@_implementationOnly import P256K
|
||||
|
||||
public enum NostrHTTPAuthError: Error, Equatable {
|
||||
case invalidHex
|
||||
|
||||
@@ -36,6 +36,13 @@ target 'Runner' do
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
require_relative 'trust_swift_plugins'
|
||||
BuzzSwiftPluginTrust.install(
|
||||
[
|
||||
File.join(__dir__, 'Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved'),
|
||||
],
|
||||
File.expand_path('~/Library/org.swift.swiftpm/security'),
|
||||
)
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
target.build_configurations.each do |config|
|
||||
|
||||
@@ -227,6 +227,6 @@ SPEC CHECKSUMS:
|
||||
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
|
||||
video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a
|
||||
|
||||
PODFILE CHECKSUM: ed10001903303a0ae660957e1d727012a3136046
|
||||
PODFILE CHECKSUM: 36153deab10e24b51e0a03a6491abddbc3bcfc8b
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"originHash" : "62fc6df0fb0a452720ac04b0bfacf7c5dbe509dd06046cc6c44487a812f0502e",
|
||||
"originHash" : "3a973186bec68a8d259cc720f0f2f4ba8fe661a4c753a8152a18075110bb26d4",
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "swift-secp256k1",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/21-DOT-DEV/swift-secp256k1.git",
|
||||
"state" : {
|
||||
"revision" : "8c62aba8a3011c9bcea232e5ee007fb0b34a15e2",
|
||||
"version" : "0.21.1"
|
||||
"revision" : "e70a10e036a55fffea31568f0af92d69b6d449cd",
|
||||
"version" : "0.23.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
41
mobile/ios/trust_swift_plugins.rb
Normal file
41
mobile/ios/trust_swift_plugins.rb
Normal file
@@ -0,0 +1,41 @@
|
||||
require 'json'
|
||||
require 'fileutils'
|
||||
require 'tempfile'
|
||||
|
||||
# Xcode records approval per plugin and package revision. Never disable plugin
|
||||
# validation globally: a dependency update must explicitly update this approval.
|
||||
module BuzzSwiftPluginTrust
|
||||
APPROVAL = {
|
||||
'fingerprint' => 'e70a10e036a55fffea31568f0af92d69b6d449cd',
|
||||
'packageIdentity' => 'swift-secp256k1',
|
||||
'targetName' => 'SharedSourcesPlugin',
|
||||
}.freeze
|
||||
PACKAGE_URL = 'https://github.com/21-DOT-DEV/swift-secp256k1.git'.freeze
|
||||
|
||||
def self.install(lockfiles, directory)
|
||||
lockfiles.each do |lockfile|
|
||||
pins = JSON.parse(File.read(lockfile)).fetch('pins')
|
||||
pin = pins.find { |entry| entry['identity'] == APPROVAL.fetch('packageIdentity') }
|
||||
unless pin && pin['location'] == PACKAGE_URL &&
|
||||
pin.fetch('state').fetch('revision') == APPROVAL.fetch('fingerprint')
|
||||
raise "Unapproved swift-secp256k1 revision in #{lockfile}; review the plugin before updating its approval"
|
||||
end
|
||||
end
|
||||
|
||||
FileUtils.mkdir_p(directory)
|
||||
path = File.join(directory, 'plugins.json')
|
||||
File.open(File.join(directory, 'buzz-plugins.lock'), File::RDWR | File::CREAT, 0o600) do |lock|
|
||||
lock.flock(File::LOCK_EX)
|
||||
approvals = File.exist?(path) ? JSON.parse(File.read(path)) : []
|
||||
raise "Expected an array in #{path}" unless approvals.is_a?(Array)
|
||||
return if approvals.include?(APPROVAL)
|
||||
|
||||
# Preserve approvals for other projects and publish a complete JSON file.
|
||||
Tempfile.create(['plugins', '.json'], directory) do |file|
|
||||
file.write(JSON.pretty_generate(approvals + [APPROVAL]) + "\n")
|
||||
file.flush
|
||||
File.rename(file.path, path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
68
scripts/test-swift-plugin-trust.rb
Normal file
68
scripts/test-swift-plugin-trust.rb
Normal file
@@ -0,0 +1,68 @@
|
||||
require 'minitest/autorun'
|
||||
require 'tmpdir'
|
||||
require_relative '../mobile/ios/trust_swift_plugins'
|
||||
|
||||
class SwiftPluginTrustTest < Minitest::Test
|
||||
def setup
|
||||
@root = Dir.mktmpdir
|
||||
@directory = File.join(@root, 'security')
|
||||
@lockfile = File.join(@root, 'Package.resolved')
|
||||
@pin = {
|
||||
'identity' => 'swift-secp256k1',
|
||||
'location' => BuzzSwiftPluginTrust::PACKAGE_URL,
|
||||
'state' => { 'revision' => BuzzSwiftPluginTrust::APPROVAL.fetch('fingerprint') },
|
||||
}
|
||||
write_pin
|
||||
end
|
||||
|
||||
def teardown
|
||||
FileUtils.remove_entry(@root)
|
||||
end
|
||||
|
||||
def write_pin
|
||||
File.write(@lockfile, JSON.generate('pins' => [@pin]))
|
||||
end
|
||||
|
||||
def install
|
||||
BuzzSwiftPluginTrust.install([@lockfile], @directory)
|
||||
end
|
||||
|
||||
def test_approves_only_the_pinned_plugin_and_is_idempotent
|
||||
install
|
||||
path = File.join(@directory, 'plugins.json')
|
||||
assert_equal [BuzzSwiftPluginTrust::APPROVAL], JSON.parse(File.read(path))
|
||||
before = File.read(path)
|
||||
install
|
||||
assert_equal before, File.read(path)
|
||||
end
|
||||
|
||||
def test_preserves_other_project_approvals
|
||||
FileUtils.mkdir_p(@directory)
|
||||
other = { 'fingerprint' => 'other', 'packageIdentity' => 'other', 'targetName' => 'OtherPlugin' }
|
||||
File.write(File.join(@directory, 'plugins.json'), JSON.generate([other]))
|
||||
install
|
||||
assert_equal [other, BuzzSwiftPluginTrust::APPROVAL], JSON.parse(File.read(File.join(@directory, 'plugins.json')))
|
||||
end
|
||||
|
||||
def test_rejects_changed_revision_before_writing_trust
|
||||
@pin['state']['revision'] = 'unreviewed'
|
||||
write_pin
|
||||
assert_raises(RuntimeError) { install }
|
||||
refute File.exist?(@directory)
|
||||
end
|
||||
|
||||
def test_rejects_another_repository_with_the_same_package_name
|
||||
@pin['location'] = 'https://example.com/swift-secp256k1.git'
|
||||
write_pin
|
||||
assert_raises(RuntimeError) { install }
|
||||
refute File.exist?(@directory)
|
||||
end
|
||||
|
||||
def test_does_not_overwrite_malformed_existing_trust
|
||||
FileUtils.mkdir_p(@directory)
|
||||
path = File.join(@directory, 'plugins.json')
|
||||
File.write(path, '{broken')
|
||||
assert_raises(JSON::ParserError) { install }
|
||||
assert_equal '{broken', File.read(path)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user