Skip to content

Soundness #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .license_header_template
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@@===----------------------------------------------------------------------===@@
@@
@@ This source file is part of the swift-libp2p open source project
@@
@@ Copyright (c) YEARS swift-libp2p project authors
@@ Licensed under MIT
@@
@@ See LICENSE for license information
@@ See CONTRIBUTORS for the list of swift-libp2p project authors
@@
@@ SPDX-License-Identifier: MIT
@@
@@===----------------------------------------------------------------------===@@
10 changes: 10 additions & 0 deletions .licenseignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.github/workflows/configs/.flake8
**/*.yml
*.md
*.txt
Package.swift
Package.resolved
.gitignore
.swift-format
.licenseignore
.license_header_template
68 changes: 68 additions & 0 deletions .swift-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"version" : 1,
"indentation" : {
"spaces" : 4
},
"tabWidth" : 4,
"fileScopedDeclarationPrivacy" : {
"accessLevel" : "private"
},
"spacesAroundRangeFormationOperators" : false,
"indentConditionalCompilationBlocks" : false,
"indentSwitchCaseLabels" : false,
"lineBreakAroundMultilineExpressionChainComponents" : false,
"lineBreakBeforeControlFlowKeywords" : false,
"lineBreakBeforeEachArgument" : true,
"lineBreakBeforeEachGenericRequirement" : true,
"lineLength" : 120,
"maximumBlankLines" : 1,
"respectsExistingLineBreaks" : true,
"prioritizeKeepingFunctionOutputTogether" : true,
"noAssignmentInExpressions" : {
"allowedFunctions" : [
"XCTAssertNoThrow",
"XCTAssertThrowsError"
]
},
"rules" : {
"AllPublicDeclarationsHaveDocumentation" : false,
"AlwaysUseLiteralForEmptyCollectionInit" : false,
"AlwaysUseLowerCamelCase" : false,
"AmbiguousTrailingClosureOverload" : true,
"BeginDocumentationCommentWithOneLineSummary" : false,
"DoNotUseSemicolons" : true,
"DontRepeatTypeInStaticProperties" : true,
"FileScopedDeclarationPrivacy" : true,
"FullyIndirectEnum" : true,
"GroupNumericLiterals" : true,
"IdentifiersMustBeASCII" : true,
"NeverForceUnwrap" : false,
"NeverUseForceTry" : false,
"NeverUseImplicitlyUnwrappedOptionals" : false,
"NoAccessLevelOnExtensionDeclaration" : true,
"NoAssignmentInExpressions" : true,
"NoBlockComments" : true,
"NoCasesWithOnlyFallthrough" : true,
"NoEmptyTrailingClosureParentheses" : true,
"NoLabelsInCasePatterns" : true,
"NoLeadingUnderscores" : false,
"NoParensAroundConditions" : true,
"NoVoidReturnOnFunctionSignature" : true,
"OmitExplicitReturns" : true,
"OneCasePerLine" : true,
"OneVariableDeclarationPerLine" : true,
"OnlyOneTrailingClosureArgument" : true,
"OrderedImports" : true,
"ReplaceForEachWithForLoop" : true,
"ReturnVoidInsteadOfEmptyTuple" : true,
"UseEarlyExits" : false,
"UseExplicitNilCheckInConditions" : false,
"UseLetInEveryBoundCaseVariable" : false,
"UseShorthandTypeNames" : true,
"UseSingleLinePropertyGetter" : false,
"UseSynthesizedInitializer" : false,
"UseTripleSlashForDocumentationComments" : true,
"UseWhereClausesInForLoops" : false,
"ValidateDocumentationComments" : false
}
}
19 changes: 19 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright (c) 2025 swift-libp2p

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.
32 changes: 23 additions & 9 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
// swift-tools-version:5.4
// The swift-tools-version declares the minimum version of Swift required to build this package.
// swift-tools-version:5.5
//===----------------------------------------------------------------------===//
//
// This source file is part of the swift-libp2p open source project
//
// Copyright (c) 2022-2025 swift-libp2p project authors
// Licensed under MIT
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of swift-libp2p project authors
//
// SPDX-License-Identifier: MIT
//
//===----------------------------------------------------------------------===//

import PackageDescription

Expand All @@ -12,14 +24,14 @@ let package = Package(
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "LibP2PIdentify",
targets: ["LibP2PIdentify"]),
targets: ["LibP2PIdentify"]
)
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(url: "https://github.com/swift-libp2p/swift-libp2p.git", .upToNextMajor(from: "0.1.0")),
.package(url: "https://github.com/swift-libp2p/swift-libp2p-mplex.git", .upToNextMajor(from: "0.1.0")),
.package(url: "https://github.com/swift-libp2p/swift-libp2p-noise.git", .upToNextMajor(from: "0.1.0"))
.package(url: "https://github.com/swift-libp2p/swift-libp2p-noise.git", .upToNextMajor(from: "0.1.0")),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
Expand All @@ -30,14 +42,16 @@ let package = Package(
.product(name: "LibP2P", package: "swift-libp2p")
],
resources: [
.copy("Protobufs/Identify.proto")
]),
.copy("Protobufs/Identify.proto")
]
),
.testTarget(
name: "LibP2PIdentifyTests",
dependencies: [
"LibP2PIdentify",
.product(name: "LibP2PNoise", package: "swift-libp2p-noise"),
.product(name: "LibP2PMPLEX", package: "swift-libp2p-mplex")
]),
.product(name: "LibP2PMPLEX", package: "swift-libp2p-mplex"),
]
),
]
)
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ Identify consists of a set of protocols used to help identify remote peers withi
- /ipfs/ping
- A ping protocol that allows for quick and easy pings to libp2p Peers for measuring latency, testing liveness/connectivity, etc.

#### Heads up ‼️
- This package is embedded into [swift-libp2p](https://github.com/swift-libp2p/swift-libp2p) . There's no need to include this package as a dependency in your swift-libp2p project.

#### For more details see
- [Multiformats / Mulitbase Spec](https://github.com/multiformats/multibase/blob/master/README.md)

Expand Down
13 changes: 10 additions & 3 deletions Sources/LibP2PIdentify/Application+Identify.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
//===----------------------------------------------------------------------===//
//
// Application+Identify.swift
//
// This source file is part of the swift-libp2p open source project
//
// Created by Brandon Toms on 4/13/22.
// Copyright (c) 2022-2025 swift-libp2p project authors
// Licensed under MIT
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of swift-libp2p project authors
//
// SPDX-License-Identifier: MIT
//
//===----------------------------------------------------------------------===//

import LibP2P

Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,42 @@
//===----------------------------------------------------------------------===//
//
// PartialIdentifyMessageDecoder.swift
//
// This source file is part of the swift-libp2p open source project
//
// Created by Brandon Toms on 4/13/22.
// Copyright (c) 2022-2025 swift-libp2p project authors
// Licensed under MIT
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of swift-libp2p project authors
//
// SPDX-License-Identifier: MIT
//
//===----------------------------------------------------------------------===//

import LibP2P
import NIO

extension Application.ChildChannelHandlers.Provider {

/// Loggers installs a set of inbound and outbound logging handlers that simply dump all data flowing through the pipeline out to the console for debugging purposes
internal static var partialIdentifyMessageHandler: Self {
.init { connection -> [ChannelHandler] in
[ByteToMessageHandler(PartialIdentifyMessageDecoder())]
}
}

}

/// Sometimes we receive an `IdentifyMessage` without the signed peer record.
/// This decoder will handle accumulating partial `IdentifyMessages` and pass them along once all parts are available, making our route handler logic simpler and cleaner.
public class PartialIdentifyMessageDecoder: ByteToMessageDecoder {
public typealias InboundOut = ByteBuffer

private var partialIdentify:IdentifyMessage? = nil
private var partialIdentify: IdentifyMessage? = nil

public func decode(context: ChannelHandlerContext, buffer: inout ByteBuffer) throws -> DecodingState {
// Make sure there's data to be read
guard buffer.readableBytes > 0 else { return .needMoreData }

//Try and decode the Identity Reponse
guard var remoteIdentify = try? IdentifyMessage(contiguousBytes: Data(buffer.readableBytesView)) else {
return .needMoreData
Expand All @@ -38,63 +45,71 @@ public class PartialIdentifyMessageDecoder: ByteToMessageDecoder {
if !remoteIdentify.publicKey.isEmpty && !remoteIdentify.signedPeerRecord.isEmpty {
// Send the message's bytes up the pipeline to the next handler.
context.fireChannelRead(self.wrapInboundOut(buffer))

// Consume the bytes
buffer.moveReaderIndex(forwardBy: buffer.readableBytes)

// We can keep going if you have more data.
return .continue

} else {
// We received a partial identify message...
if !remoteIdentify.publicKey.isEmpty && remoteIdentify.signedPeerRecord.isEmpty {
// If this message contains the pubkey without the signature then store it in our cache
self.partialIdentify = remoteIdentify

// Consume the bytes
buffer.moveReaderIndex(forwardBy: buffer.readableBytes)

// Wait for the remainder of the IdentifyMessage to come in...
return .needMoreData

} else if !remoteIdentify.signedPeerRecord.isEmpty && remoteIdentify.publicKey.isEmpty, var cachedIdentify = self.partialIdentify {
} else if !remoteIdentify.signedPeerRecord.isEmpty && remoteIdentify.publicKey.isEmpty,
var cachedIdentify = self.partialIdentify
{
// If this message contains the signature without the pubkey, append the sig to the cached entry and attempt to validate
cachedIdentify.signedPeerRecord = remoteIdentify.signedPeerRecord

// Swap the remote identify message with the cached version and append the signedPeerRecord
remoteIdentify = cachedIdentify

// Consume the bytes
buffer.moveReaderIndex(forwardBy: buffer.readableBytes)

// Send the message's bytes up the pipeline to the next handler.
context.fireChannelRead(self.wrapInboundOut(ByteBuffer(bytes: try remoteIdentify.serializedData().bytes)))

context.fireChannelRead(
self.wrapInboundOut(ByteBuffer(bytes: try remoteIdentify.serializedData().bytes))
)

// We can keep going if you have more data.
return .continue

} else {
//print("PartialIdentifyMessageHandler:SignedPeerRecord is nil: \(remoteIdentify.signedPeerRecord.isEmpty)")
//print("PartialIdentifyMessageHandler:PublicKey is nil: \(remoteIdentify.publicKey.isEmpty)")
//print(remoteIdentify)

// Partial identify message received and we're not sure what to do with it...
context.fireErrorCaught(Errors.invalidPartialIdentifyMessage)

// Consume the bytes
buffer.moveReaderIndex(forwardBy: buffer.readableBytes)

// We can keep going if you have more data.
return .continue
}
}
}

public func decodeLast(context: ChannelHandlerContext, buffer: inout ByteBuffer, seenEOF: Bool) throws -> DecodingState {
return try decode(context: context, buffer: &buffer)
public func decodeLast(
context: ChannelHandlerContext,
buffer: inout ByteBuffer,
seenEOF: Bool
) throws -> DecodingState {
try decode(context: context, buffer: &buffer)
}
public enum Errors:Error {

public enum Errors: Error {
case invalidPartialIdentifyMessage
case invalidIdentifyMessage
}
Expand Down
Loading
Loading