diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 61753eab7..000000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,39 +0,0 @@ -# This workflow will build a Java project with Maven -# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven - -name: Java CI with Maven and Deploy - -on: - push: - branches: [ master ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Set up JDK 11 for Maven Central - uses: actions/setup-java@v3 - with: - distribution: 'zulu' - java-version: '11' - architecture: x64 - server-id: ossrh - gpg-private-key: ${{ secrets.GPG_SECRET_KEY }} - gpg-passphrase: MAVEN_GPG_PASSPHRASE - server-username: MAVEN_USERNAME - server-password: MAVEN_CENTRAL_TOKEN - - name: Setup git profile - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" - - name: Publish Snapshot to Maven Central - run: mvn deploy -B -Possrh - env: - MAVEN_USERNAME: hap-java-dev - MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }} - MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - - name: Publish site - run: mvn -B site-deploy -Dusername=github-actions -Dpassword=${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml deleted file mode 100644 index 6f597043c..000000000 --- a/.github/workflows/maven.yml +++ /dev/null @@ -1,24 +0,0 @@ -# This workflow will build a Java project with Maven -# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven - -name: Java CI with Maven - -on: - pull_request: - branches: [ master ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - distribution: 'zulu' - java-version: '11' - architecture: x64 - - name: Build with Maven - run: mvn -B package --file pom.xml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 48b5ee7cf..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,40 +0,0 @@ -# This workflow will build a Java project with Maven -# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven - -name: Stage Release on Master Branch - -on: - workflow_dispatch: - inputs: - releaseVersion: - description: Version to release - required: true - -permissions: - contents: write - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - uses: git-actions/set-user@v1 - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - distribution: 'zulu' - java-version: '11' - architecture: x64 - server-id: ossrh - gpg-private-key: ${{ secrets.GPG_SECRET_KEY }} - gpg-passphrase: MAVEN_GPG_PASSPHRASE - server-username: MAVEN_USERNAME - server-password: MAVEN_CENTRAL_TOKEN - - name: Maven release - run: mvn release:prepare release:perform -B -DreleaseVersion=${{ github.event.inputs.releaseVersion }} -Possrh - env: - MAVEN_USERNAME: hap-java-dev - MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }} - MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/CHANGES.md b/CHANGES.md index ab4bc7e4f..e7d226df4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -62,6 +62,7 @@ * Valid values are supported for enum characteristics instead of min and max values * Supported valid states for Thermostat, SecuritySystem, HeaterCooler and HumidifierDehumidifier [#108] [#120](https://github.com/hap-java/HAP-Java/pull/120) * Support for FilterMaintenance. Can be used as a linked service for an Air Purifier [#124](https://github.com/hap-java/HAP-Java/pull/124) +* Update crypto libs [#130](https://github.com/hap-java/HAP-Java/pull/130) ## Fixes diff --git a/pom.xml b/pom.xml index ffd5798a3..600cb07a7 100644 --- a/pom.xml +++ b/pom.xml @@ -1,358 +1,300 @@ - 4.0.0 - io.github.hap-java - hap - hap-java - Homekit Accessory Protocol for Java - 2.0.8-SNAPSHOT - jar - https://github.com/hap-java/HAP-Java + 4.0.0 + io.github.hap-java + hap + hap-java + Homekit Accessory Protocol for Java + 2.0.4-rako + jar + https://github.com/hap-java/HAP-Java - - UTF-8 - 4.1.72.Final - + + UTF-8 + 4.1.121.Final + - - - MIT License - http://www.opensource.org/licenses/mit-license.php - repo - - + + + MIT License + http://www.opensource.org/licenses/mit-license.php + repo + + - - scm:git:https://github.com/hap-java/HAP-Java.git - scm:git:https://github.com/hap-java/HAP-Java.git - https://github.com/hap-java/HAP-Java.git - HEAD - + + scm:git:https://github.com/hap-java/HAP-Java.git + scm:git:https://github.com/hap-java/HAP-Java.git + https://github.com/hap-java/HAP-Java.git + HEAD + - - - Andy Lintner - dev@beowulfe.com - https://github.com/beowulfe - - - Cody Cutrer - cody@cutrer.us - https://github.com/ccutrer - - - Tim Harper - timcharper@gmail.com - https://github.com/timcharper - - + + + Andy Lintner + dev@beowulfe.com + https://github.com/beowulfe + + + Cody Cutrer + cody@cutrer.us + https://github.com/ccutrer + + + Tim Harper + timcharper@gmail.com + https://github.com/timcharper + + - + - - org.slf4j - slf4j-api - 1.7.10 - + + org.slf4j + slf4j-api + 1.7.10 + - - io.netty - netty-common - ${netty.version} - + + io.netty + netty-common + ${netty.version} + - - io.netty - netty-buffer - ${netty.version} - + + io.netty + netty-buffer + ${netty.version} + - - io.netty - netty-transport - ${netty.version} - + + io.netty + netty-transport + ${netty.version} + - - io.netty - netty-handler - ${netty.version} - + + io.netty + netty-handler + ${netty.version} + - - io.netty - netty-codec - ${netty.version} - + + io.netty + netty-codec + ${netty.version} + - - io.netty - netty-codec-http - ${netty.version} - + + io.netty + netty-codec-http + ${netty.version} + - - io.netty - netty-resolver - ${netty.version} - + + io.netty + netty-resolver + ${netty.version} + - - com.nimbusds - srp6a - 1.5.2 - + + com.nimbusds + srp6a + 2.1.0 + - - org.bouncycastle - bcprov-jdk15on - 1.51 - + + org.bouncycastle + bcprov-jdk15on + 1.69 + - - net.vrallev.ecc - ecc-25519-java - 1.0.1 - + + net.vrallev.ecc + ecc-25519-java + 1.0.3 + - - org.zeromq - curve25519-java - 0.1.0 - + + javax.json + javax.json-api + 1.1.4 + - - javax.json - javax.json-api - 1.0 - + + org.glassfish + javax.json + 1.1.4 + - - org.glassfish - javax.json - 1.0.4 - + + org.jmdns + jmdns + 3.5.8 + - - org.jmdns - jmdns - 3.5.6 - - - - junit - junit - 4.13.1 - test - - - - org.mockito - mockito-core - 3.8.0 - test - + + org.mockito + mockito-core + 3.8.0 + test + - - org.assertj - assertj-core - 3.19.0 - test - + + org.assertj + assertj-core + 3.19.0 + test + + + org.junit.jupiter + junit-jupiter + 5.10.0 + test + - + - - - - com.coveo - fmt-maven-plugin - 2.9 - - - - format - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.0 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.2.0 - - io.github.hapjava.server.impl - 8 - - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-scm-publish-plugin - 3.1.0 - - - scm-publish - site-deploy - - publish-scm - - - scm:git:https://github.com/hap-java/HAP-Java.git - gh-pages - - - - - - org.apache.maven.plugins - maven-site-plugin - 3.7.1 - - - stage-for-scm-publish - post-site - - stage - - - false - - - - - + + + + com.coveo + fmt-maven-plugin + 2.9 + + + + format + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + attach-sources + + jar-no-fork + + + + + + - - - - org.apache.maven.plugins - maven-site-plugin - - true - - - - + + + + org.apache.maven.plugins + maven-site-plugin + + true + + + + - + - - - website - https://hap-java.github.io/ - - - ossrh - https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ - - - ossrh - https://s01.oss.sonatype.org/content/repositories/snapshots - - + + + website + https://hap-java.github.io/ + + + ossrh + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + + + ossrh + https://s01.oss.sonatype.org/content/repositories/snapshots + + - - - - org.apache.maven.plugins - maven-pmd-plugin - 3.6 - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.0.1 - - io.github.hapjava.server.impl - 8 - false - - - - - javadoc - - - - - - org.codehaus.mojo - findbugs-maven-plugin - 3.0.3 - - - + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.6 + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.0.1 + + io.github.hapjava.server.impl + 8 + false + + + + + javadoc + + + + + + org.codehaus.mojo + findbugs-maven-plugin + 3.0.3 + + + - - - ossrh - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.5 - - - sign-artifacts - verify - - sign - - - - - HAP-Java - - --pinentry-mode - loopback - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.3 - true - - ossrh - https://s01.oss.sonatype.org/ - true - - - - - - + + + ossrh + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + HAP-Java + + --pinentry-mode + loopback + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.3 + true + + ossrh + https://s01.oss.sonatype.org/ + true + + + + + + diff --git a/pom.xml.versionsBackup b/pom.xml.versionsBackup new file mode 100644 index 000000000..fee8f26c1 --- /dev/null +++ b/pom.xml.versionsBackup @@ -0,0 +1,300 @@ + + + 4.0.0 + io.github.hap-java + hap + hap-java + Homekit Accessory Protocol for Java + 2.0.3-rako + jar + https://github.com/hap-java/HAP-Java + + + UTF-8 + 4.1.121.Final + + + + + MIT License + http://www.opensource.org/licenses/mit-license.php + repo + + + + + scm:git:https://github.com/hap-java/HAP-Java.git + scm:git:https://github.com/hap-java/HAP-Java.git + https://github.com/hap-java/HAP-Java.git + HEAD + + + + + Andy Lintner + dev@beowulfe.com + https://github.com/beowulfe + + + Cody Cutrer + cody@cutrer.us + https://github.com/ccutrer + + + Tim Harper + timcharper@gmail.com + https://github.com/timcharper + + + + + + + org.slf4j + slf4j-api + 1.7.10 + + + + io.netty + netty-common + ${netty.version} + + + + io.netty + netty-buffer + ${netty.version} + + + + io.netty + netty-transport + ${netty.version} + + + + io.netty + netty-handler + ${netty.version} + + + + io.netty + netty-codec + ${netty.version} + + + + io.netty + netty-codec-http + ${netty.version} + + + + io.netty + netty-resolver + ${netty.version} + + + + com.nimbusds + srp6a + 2.1.0 + + + + org.bouncycastle + bcprov-jdk15on + 1.69 + + + + net.vrallev.ecc + ecc-25519-java + 1.0.3 + + + + javax.json + javax.json-api + 1.1.4 + + + + org.glassfish + javax.json + 1.1.4 + + + + org.jmdns + jmdns + 3.5.8 + + + + org.mockito + mockito-core + 3.8.0 + test + + + + org.assertj + assertj-core + 3.19.0 + test + + + org.junit.jupiter + junit-jupiter + 5.10.0 + test + + + + + + + + com.coveo + fmt-maven-plugin + 2.9 + + + + format + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + attach-sources + + jar-no-fork + + + + + + + + + + + org.apache.maven.plugins + maven-site-plugin + + true + + + + + + + + + + website + https://hap-java.github.io/ + + + ossrh + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + + + ossrh + https://s01.oss.sonatype.org/content/repositories/snapshots + + + + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.6 + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.0.1 + + io.github.hapjava.server.impl + 8 + false + + + + + javadoc + + + + + + org.codehaus.mojo + findbugs-maven-plugin + 3.0.3 + + + + + + + ossrh + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + HAP-Java + + --pinentry-mode + loopback + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.3 + true + + ossrh + https://s01.oss.sonatype.org/ + true + + + + + + + + diff --git a/src/main/java/io/github/hapjava/accessories/HomekitAccessory.java b/src/main/java/io/github/hapjava/accessories/HomekitAccessory.java index 64c406492..a8d01254e 100644 --- a/src/main/java/io/github/hapjava/accessories/HomekitAccessory.java +++ b/src/main/java/io/github/hapjava/accessories/HomekitAccessory.java @@ -23,7 +23,7 @@ public interface HomekitAccessory { * * @return the unique identifier. */ - int getId(); + long getId(); /** * Returns a name to display in iOS. diff --git a/src/main/java/io/github/hapjava/characteristics/impl/base/IntegerCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/base/IntegerCharacteristic.java index 6d1b7df6d..e80c14823 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/base/IntegerCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/base/IntegerCharacteristic.java @@ -56,6 +56,32 @@ public IntegerCharacteristic( this.setter = setter; } + public IntegerCharacteristic( + String type, + String description, + int minValue, + int maxValue, + String format, + String unit, + Optional>> getter, + Optional> setter, + Optional> subscriber, + Optional unsubscriber) { + super( + type, + format, + description, + getter.isPresent(), + setter.isPresent(), + subscriber, + unsubscriber); + this.minValue = minValue; + this.maxValue = maxValue; + this.unit = unit; + this.getter = getter; + this.setter = setter; + } + /** {@inheritDoc} */ @Override protected CompletableFuture makeBuilder(int iid) { @@ -77,7 +103,9 @@ public CompletableFuture getValue() { @Override public void setValue(Integer value) throws Exception { - if (setter.isPresent()) setter.get().accept(value); + if (setter.isPresent()) { + setter.get().accept(value); + } } /** {@inheritDoc} */ diff --git a/src/main/java/io/github/hapjava/characteristics/impl/battery/BatteryLevelCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/battery/BatteryLevelCharacteristic.java index 0fa56ff40..cb4f335a2 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/battery/BatteryLevelCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/battery/BatteryLevelCharacteristic.java @@ -21,7 +21,7 @@ public BatteryLevelCharacteristic( "battery level", 0, 100, - "%", + "percentage", Optional.of(getter), Optional.empty(), Optional.of(subscriber), diff --git a/src/main/java/io/github/hapjava/characteristics/impl/common/ServiceLabelIndexCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/common/ServiceLabelIndexCharacteristic.java index 522cb04fe..955e032d5 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/common/ServiceLabelIndexCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/common/ServiceLabelIndexCharacteristic.java @@ -19,7 +19,7 @@ public ServiceLabelIndexCharacteristic(Supplier> gett "service label index", 0, 100, - "%", + "percentage", Optional.of(getter), Optional.empty(), Optional.empty(), diff --git a/src/main/java/io/github/hapjava/characteristics/impl/common/WaterLavelCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/common/WaterLavelCharacteristic.java index dda11b087..121ac013e 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/common/WaterLavelCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/common/WaterLavelCharacteristic.java @@ -22,7 +22,7 @@ public WaterLavelCharacteristic( 0, 100, 1, - "%", + "percentage", Optional.of(getter), Optional.empty(), Optional.of(subscriber), diff --git a/src/main/java/io/github/hapjava/characteristics/impl/fan/RotationSpeedCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/fan/RotationSpeedCharacteristic.java index d7a1d6929..7ef05a13c 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/fan/RotationSpeedCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/fan/RotationSpeedCharacteristic.java @@ -30,7 +30,7 @@ public RotationSpeedCharacteristic( minValue, maxValue, minStep, - "%", + "percentage", Optional.of(getter), Optional.of(setter), Optional.of(subscriber), diff --git a/src/main/java/io/github/hapjava/characteristics/impl/filtermaintenance/FilterLifeLevelCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/filtermaintenance/FilterLifeLevelCharacteristic.java index 29cdf8d6e..0206a7193 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/filtermaintenance/FilterLifeLevelCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/filtermaintenance/FilterLifeLevelCharacteristic.java @@ -21,7 +21,7 @@ public FilterLifeLevelCharacteristic( 0, 100, 1, - "%", + "percentage", Optional.of(getter), Optional.empty(), Optional.of(subscriber), diff --git a/src/main/java/io/github/hapjava/characteristics/impl/humidifier/HumidityDehumidifierThresholdCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/humidifier/HumidityDehumidifierThresholdCharacteristic.java index b8a4ca569..9839fb9fd 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/humidifier/HumidityDehumidifierThresholdCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/humidifier/HumidityDehumidifierThresholdCharacteristic.java @@ -25,7 +25,7 @@ public HumidityDehumidifierThresholdCharacteristic( 0, 100, 1, - "%", + "percentage", Optional.of(getter), Optional.of(setter), Optional.of(subscriber), diff --git a/src/main/java/io/github/hapjava/characteristics/impl/humidifier/HumidityHumidifierThresholdCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/humidifier/HumidityHumidifierThresholdCharacteristic.java index 2ee8adbf2..40401352a 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/humidifier/HumidityHumidifierThresholdCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/humidifier/HumidityHumidifierThresholdCharacteristic.java @@ -25,7 +25,7 @@ public HumidityHumidifierThresholdCharacteristic( 0, 100, 1, - "%", + "percentage", Optional.of(getter), Optional.of(setter), Optional.of(subscriber), diff --git a/src/main/java/io/github/hapjava/characteristics/impl/humiditysensor/CurrentRelativeHumidityCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/humiditysensor/CurrentRelativeHumidityCharacteristic.java index be77125b6..71466c424 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/humiditysensor/CurrentRelativeHumidityCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/humiditysensor/CurrentRelativeHumidityCharacteristic.java @@ -20,7 +20,7 @@ public CurrentRelativeHumidityCharacteristic( 0, 100, 1, - "%", + "percentage", Optional.of(getter), Optional.empty(), Optional.of(subscriber), diff --git a/src/main/java/io/github/hapjava/characteristics/impl/humiditysensor/TargetRelativeHumidityCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/humiditysensor/TargetRelativeHumidityCharacteristic.java index ab8ad7e29..ad4f35858 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/humiditysensor/TargetRelativeHumidityCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/humiditysensor/TargetRelativeHumidityCharacteristic.java @@ -22,7 +22,7 @@ public TargetRelativeHumidityCharacteristic( 0, 100, 1, - "%", + "percentage", Optional.of(getter), Optional.of(setter), Optional.of(subscriber), diff --git a/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/BrightnessCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/BrightnessCharacteristic.java index 693e42efc..1da361a5f 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/BrightnessCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/BrightnessCharacteristic.java @@ -26,7 +26,7 @@ public BrightnessCharacteristic( "level of brightness", 0, 100, - "%", + "percentage", Optional.of(getter), Optional.of(setter), Optional.of(subscriber), diff --git a/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/ColorTemperatureCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/ColorTemperatureCharacteristic.java index 987ab5eee..31b7cd64a 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/ColorTemperatureCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/ColorTemperatureCharacteristic.java @@ -12,8 +12,8 @@ /** This characteristic describes color temperature in mireds */ public class ColorTemperatureCharacteristic extends IntegerCharacteristic implements EventableCharacteristic { - public static final int DEFAULT_MIN_VALUE = 50; - public static final int DEFAULT_MAX_VALUE = 400; + public static final int DEFAULT_MIN_VALUE = 100; + public static final int DEFAULT_MAX_VALUE = 555; public ColorTemperatureCharacteristic( int minValue, @@ -27,7 +27,8 @@ public ColorTemperatureCharacteristic( "color temperature", minValue, maxValue, - "mired", + "uint32", + null, Optional.of(getter), Optional.of(setter), Optional.of(subscriber), diff --git a/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/SaturationCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/SaturationCharacteristic.java index 90694ef98..a6ff31f4b 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/SaturationCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/lightbulb/SaturationCharacteristic.java @@ -24,7 +24,7 @@ public SaturationCharacteristic( 0, 100, 1, - "%", + "percentage", Optional.of(getter), Optional.of(setter), Optional.of(subscriber), diff --git a/src/main/java/io/github/hapjava/characteristics/impl/protocolinformation/VersionCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/protocolinformation/VersionCharacteristic.java new file mode 100644 index 000000000..fcc33016d --- /dev/null +++ b/src/main/java/io/github/hapjava/characteristics/impl/protocolinformation/VersionCharacteristic.java @@ -0,0 +1,19 @@ +package io.github.hapjava.characteristics.impl.protocolinformation; + +import io.github.hapjava.characteristics.impl.base.StaticStringCharacteristic; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; + +/** This characteristic contains a version string. */ +public class VersionCharacteristic extends StaticStringCharacteristic { + + public VersionCharacteristic(Supplier> getter) { + super( + "00000037‐0000‐1000‐8000‐0026BB765291", + "version", + Optional.of(getter), + Optional.empty(), + Optional.empty()); + } +} diff --git a/src/main/java/io/github/hapjava/characteristics/impl/windowcovering/CurrentPositionCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/windowcovering/CurrentPositionCharacteristic.java index d51614615..5f8f50081 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/windowcovering/CurrentPositionCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/windowcovering/CurrentPositionCharacteristic.java @@ -21,7 +21,7 @@ public CurrentPositionCharacteristic( "current position", 0, 100, - "%", + "percentage", Optional.of(getter), Optional.empty(), Optional.of(subscriber), diff --git a/src/main/java/io/github/hapjava/characteristics/impl/windowcovering/TargetPositionCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/windowcovering/TargetPositionCharacteristic.java index 6398a0b37..9458402aa 100644 --- a/src/main/java/io/github/hapjava/characteristics/impl/windowcovering/TargetPositionCharacteristic.java +++ b/src/main/java/io/github/hapjava/characteristics/impl/windowcovering/TargetPositionCharacteristic.java @@ -23,7 +23,8 @@ public TargetPositionCharacteristic( "target position", 0, 100, - "%", + "uint8", + "percentage", Optional.of(getter), Optional.of(setter), Optional.of(subscriber), diff --git a/src/main/java/io/github/hapjava/server/HomekitAuthInfo.java b/src/main/java/io/github/hapjava/server/HomekitAuthInfo.java index 6441962d7..10ac5d8c9 100644 --- a/src/main/java/io/github/hapjava/server/HomekitAuthInfo.java +++ b/src/main/java/io/github/hapjava/server/HomekitAuthInfo.java @@ -4,7 +4,7 @@ import io.github.hapjava.server.impl.crypto.HAPSetupCodeUtils; import java.math.BigInteger; import java.util.Collection; -import java.util.List; +import java.util.Collections; /** * Authentication info that must be provided when constructing a new {@link HomekitServer}. You will @@ -99,7 +99,7 @@ default void createUser(String username, byte[] publicKey) { * @return the previously stored list of users. */ default Collection listUsers() { - return List.of(); + return Collections.EMPTY_LIST; } /** diff --git a/src/main/java/io/github/hapjava/server/impl/HomekitBridge.java b/src/main/java/io/github/hapjava/server/impl/HomekitBridge.java index 11efb0d37..807a7ff51 100644 --- a/src/main/java/io/github/hapjava/server/impl/HomekitBridge.java +++ b/src/main/java/io/github/hapjava/server/impl/HomekitBridge.java @@ -21,7 +21,8 @@ public HomekitBridge( String model, String manufacturer, String firmwareRevision, - String hardwareRevision) { + String hardwareRevision, + String version) { this.label = label; this.serialNumber = serialNumber; this.model = model; @@ -55,13 +56,19 @@ public CompletableFuture getFirmwareRevision() { return CompletableFuture.completedFuture(firmwareRevision); } + public CompletableFuture getHardwareRevision() { + return CompletableFuture.completedFuture(hardwareRevision); + } + @Override public Collection getServices() { + // return Collections.singleton(new ProtocolInformationService(this)); + return Collections.emptyList(); } @Override - public int getId() { + public long getId() { return 1; } } diff --git a/src/main/java/io/github/hapjava/server/impl/HomekitRegistry.java b/src/main/java/io/github/hapjava/server/impl/HomekitRegistry.java index 3c70cfb9e..5ef547923 100644 --- a/src/main/java/io/github/hapjava/server/impl/HomekitRegistry.java +++ b/src/main/java/io/github/hapjava/server/impl/HomekitRegistry.java @@ -21,7 +21,7 @@ public class HomekitRegistry { private final String label; private final SubscriptionManager subscriptions; - private final Map accessories; + private final Map accessories; private final Map> services = new HashMap<>(); private final Map> characteristics = new HashMap<>(); @@ -79,11 +79,11 @@ public Collection getAccessories() { return accessories.values(); } - public Map getServices(Integer aid) { + public Map getServices(Long aid) { return Collections.unmodifiableMap(services.get(accessories.get(aid))); } - public Map getCharacteristics(Integer aid) { + public Map getCharacteristics(Long aid) { Map characteristics = this.characteristics.get(accessories.get(aid)); if (characteristics == null) { return Collections.emptyMap(); diff --git a/src/main/java/io/github/hapjava/server/impl/HomekitRoot.java b/src/main/java/io/github/hapjava/server/impl/HomekitRoot.java index 36bfeefa2..884ed9268 100644 --- a/src/main/java/io/github/hapjava/server/impl/HomekitRoot.java +++ b/src/main/java/io/github/hapjava/server/impl/HomekitRoot.java @@ -38,6 +38,7 @@ public class HomekitRoot { private int configurationIndex = 1; private int nestedBatches = 0; private boolean madeChanges = false; + private int stateIndex = 1; HomekitRoot( String label, HomekitWebHandler webHandler, InetAddress host, HomekitAuthInfo authInfo) @@ -94,13 +95,17 @@ public class HomekitRoot { * completeUpdateBatch in order to publish all accumulated changes. */ public synchronized void batchUpdate() { - if (this.nestedBatches == 0) madeChanges = false; + if (this.nestedBatches == 0) { + madeChanges = false; + } ++this.nestedBatches; } /** Publish accumulated accessory changes since batchUpdate() was called. */ public synchronized void completeUpdateBatch() { - if (--this.nestedBatches == 0 && madeChanges) registry.reset(); + if (--this.nestedBatches == 0 && madeChanges) { + registry.reset(); + } } /** @@ -176,7 +181,8 @@ public void start() { authInfo.getMac(), port, configurationIndex, - authInfo.getSetupId()); + authInfo.getSetupId(), + this.stateIndex); } catch (Exception e) { throw new RuntimeException(e); } @@ -232,7 +238,14 @@ public void setConfigurationIndex(int revision) throws IOException { } } - HomekitRegistry getRegistry() { + public void setStateIndex(int stateIndex) throws IOException { + this.stateIndex = stateIndex; + if (this.started) { + advertiser.setStateIndex(stateIndex); + } + } + + public HomekitRegistry getRegistry() { return registry; } } diff --git a/src/main/java/io/github/hapjava/server/impl/HomekitServer.java b/src/main/java/io/github/hapjava/server/impl/HomekitServer.java index fc8ecaf76..b65659a11 100644 --- a/src/main/java/io/github/hapjava/server/impl/HomekitServer.java +++ b/src/main/java/io/github/hapjava/server/impl/HomekitServer.java @@ -27,6 +27,9 @@ */ public class HomekitServer { + public static final String PROTOCOL_VERSION = "1.1.0"; + public static final String PROTOCOL_VERSION_BONJOUR = "1.1"; + private final HomekitHttpServer http; private final InetAddress localAddress; private final JmDNS jmdns; @@ -117,13 +120,15 @@ public HomekitStandaloneAccessoryServer createStandaloneAccessory( return new HomekitStandaloneAccessoryServer(accessory, http, localAddress, authInfo); } } + public HomekitStandaloneAccessoryServer createStandaloneAccessory( HomekitAuthInfo authInfo, HomekitAccessory accessory, int category) throws IOException, ExecutionException, InterruptedException { if (jmdns != null) { return new HomekitStandaloneAccessoryServer(accessory, http, jmdns, authInfo, category); } else { - return new HomekitStandaloneAccessoryServer(accessory, http, localAddress, authInfo, category); + return new HomekitStandaloneAccessoryServer( + accessory, http, localAddress, authInfo, category); } } @@ -163,7 +168,13 @@ public HomekitRoot createBridge( } root.addAccessory( new HomekitBridge( - label, serialNumber, model, manufacturer, firmwareRevision, hardwareRevision)); + label, + serialNumber, + model, + manufacturer, + firmwareRevision, + hardwareRevision, + PROTOCOL_VERSION)); return root; } diff --git a/src/main/java/io/github/hapjava/server/impl/HomekitStandaloneAccessoryServer.java b/src/main/java/io/github/hapjava/server/impl/HomekitStandaloneAccessoryServer.java index 99ff7b746..4a5dbabee 100644 --- a/src/main/java/io/github/hapjava/server/impl/HomekitStandaloneAccessoryServer.java +++ b/src/main/java/io/github/hapjava/server/impl/HomekitStandaloneAccessoryServer.java @@ -40,7 +40,7 @@ public class HomekitStandaloneAccessoryServer { root = new HomekitRoot(accessory.getName().get(), webHandler, jmdns, authInfo); root.addAccessory(accessory); } - + HomekitStandaloneAccessoryServer( HomekitAccessory accessory, HomekitWebHandler webHandler, diff --git a/src/main/java/io/github/hapjava/server/impl/HomekitUtils.java b/src/main/java/io/github/hapjava/server/impl/HomekitUtils.java index 9b5b2b8ee..20a697ff9 100644 --- a/src/main/java/io/github/hapjava/server/impl/HomekitUtils.java +++ b/src/main/java/io/github/hapjava/server/impl/HomekitUtils.java @@ -2,7 +2,6 @@ import com.nimbusds.srp6.SRP6Routines; import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; import java.security.SecureRandom; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -14,11 +13,12 @@ public class HomekitUtils { private static volatile SecureRandom secureRandom; public static BigInteger generateSalt() { - return new BigInteger(SRP6Routines.generateRandomSalt(16)); + return new BigInteger(new SRP6Routines().generateRandomSalt(16)); } - public static byte[] generateKey() throws InvalidAlgorithmParameterException { - EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512"); + public static byte[] generateKey() { + EdDSAParameterSpec spec = + EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512); byte[] seed = new byte[spec.getCurve().getField().getb() / 8]; getSecureRandom().nextBytes(seed); return seed; diff --git a/src/main/java/io/github/hapjava/server/impl/connections/PendingNotification.java b/src/main/java/io/github/hapjava/server/impl/connections/PendingNotification.java index ea9c69305..85397f5bb 100644 --- a/src/main/java/io/github/hapjava/server/impl/connections/PendingNotification.java +++ b/src/main/java/io/github/hapjava/server/impl/connections/PendingNotification.java @@ -3,11 +3,11 @@ import io.github.hapjava.characteristics.EventableCharacteristic; public class PendingNotification { - public int aid; + public long aid; public int iid; public EventableCharacteristic characteristic; - public PendingNotification(int aid, int iid, EventableCharacteristic characteristic) { + public PendingNotification(long aid, int iid, EventableCharacteristic characteristic) { this.aid = aid; this.iid = iid; this.characteristic = characteristic; diff --git a/src/main/java/io/github/hapjava/server/impl/connections/SubscriptionManager.java b/src/main/java/io/github/hapjava/server/impl/connections/SubscriptionManager.java index 9399295fb..4eeba81ac 100644 --- a/src/main/java/io/github/hapjava/server/impl/connections/SubscriptionManager.java +++ b/src/main/java/io/github/hapjava/server/impl/connections/SubscriptionManager.java @@ -22,9 +22,10 @@ public class SubscriptionManager { private static class ConnectionsWithIds { Set connections; - int aid, iid; + long aid; + int iid; - ConnectionsWithIds(int aid, int iid) { + ConnectionsWithIds(long aid, int iid) { this.aid = aid; this.iid = iid; this.connections = new HashSet<>(); @@ -39,7 +40,7 @@ private static class ConnectionsWithIds { private int nestedBatches = 0; public synchronized void addSubscription( - int aid, + long aid, int iid, EventableCharacteristic characteristic, HomekitClientConnection connection) { @@ -139,7 +140,7 @@ private void flushUpdateBatch() { pendingNotifications.clear(); } - public synchronized void publish(int accessoryId, int iid, EventableCharacteristic changed) { + public synchronized void publish(long accessoryId, int iid, EventableCharacteristic changed) { final ConnectionsWithIds subscribers = subscriptions.get(changed); if (subscribers == null || subscribers.connections.isEmpty()) { LOGGER.trace("No subscribers to characteristic {} at accessory {} ", changed, accessoryId); @@ -233,7 +234,7 @@ public synchronized void resync(HomekitRegistry registry) { subscriptions.putAll(newSubscriptions); } - private void subscribe(int aid, int iid, EventableCharacteristic characteristic) { + private void subscribe(long aid, int iid, EventableCharacteristic characteristic) { characteristic.subscribe( () -> { publish(aid, iid, characteristic); diff --git a/src/main/java/io/github/hapjava/server/impl/crypto/ChachaDecoder.java b/src/main/java/io/github/hapjava/server/impl/crypto/ChachaDecoder.java index 4c74a469d..d616d2e0f 100644 --- a/src/main/java/io/github/hapjava/server/impl/crypto/ChachaDecoder.java +++ b/src/main/java/io/github/hapjava/server/impl/crypto/ChachaDecoder.java @@ -5,8 +5,6 @@ import org.bouncycastle.crypto.generators.Poly1305KeyGenerator; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.crypto.tls.AlertDescription; -import org.bouncycastle.crypto.tls.TlsFatalAlert; import org.bouncycastle.util.Arrays; public class ChachaDecoder { @@ -28,7 +26,7 @@ public byte[] decodeCiphertext(byte[] receivedMAC, byte[] additionalData, byte[] byte[] calculatedMAC = PolyKeyCreator.create(macKey, additionalData, ciphertext); if (!Arrays.constantTimeAreEqual(calculatedMAC, receivedMAC)) { - throw new TlsFatalAlert(AlertDescription.bad_record_mac); + throw new IOException("received an incorrect MAC"); } byte[] output = new byte[ciphertext.length]; diff --git a/src/main/java/io/github/hapjava/server/impl/http/impl/AccessoryHandler.java b/src/main/java/io/github/hapjava/server/impl/http/impl/AccessoryHandler.java index 6b840c713..ede93d271 100644 --- a/src/main/java/io/github/hapjava/server/impl/http/impl/AccessoryHandler.java +++ b/src/main/java/io/github/hapjava/server/impl/http/impl/AccessoryHandler.java @@ -42,6 +42,7 @@ public void channelActive(ChannelHandlerContext ctx) throws Exception { @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { + this.connection.close(); LOGGER.trace("Terminated HomeKit connection from " + ctx.channel().remoteAddress().toString()); super.channelInactive(ctx); } diff --git a/src/main/java/io/github/hapjava/server/impl/http/impl/HomekitHttpServer.java b/src/main/java/io/github/hapjava/server/impl/http/impl/HomekitHttpServer.java index 085d632cf..3eef12c2b 100644 --- a/src/main/java/io/github/hapjava/server/impl/http/impl/HomekitHttpServer.java +++ b/src/main/java/io/github/hapjava/server/impl/http/impl/HomekitHttpServer.java @@ -17,6 +17,7 @@ public void stop() { if (this.service != null) { this.service.shutdown(); } + this.service = null; } public HomekitHttpServer(InetAddress localAddress, int port, int nThreads) { diff --git a/src/main/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiser.java b/src/main/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiser.java index 9086acb3e..eb78c854d 100644 --- a/src/main/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiser.java +++ b/src/main/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiser.java @@ -20,6 +20,7 @@ public class JmdnsHomekitAdvertiser { private boolean discoverable = true; private static final Logger logger = LoggerFactory.getLogger(JmdnsHomekitAdvertiser.class); private boolean isAdvertising = false; + private boolean isStarted = false; private String label; private String mac; @@ -28,6 +29,7 @@ public class JmdnsHomekitAdvertiser { private int configurationIndex; private ServiceInfo serviceInfo; private int category; + private int stateIndex = 1; public JmdnsHomekitAdvertiser(JmDNS jmdns) { this.jmdns = jmdns; @@ -38,7 +40,13 @@ public JmdnsHomekitAdvertiser(InetAddress localAddress) throws UnknownHostExcept } public synchronized void advertise( - String label, int category, String mac, int port, int configurationIndex, String setupId) + String label, + int category, + String mac, + int port, + int configurationIndex, + String setupId, + int stateIndex) throws Exception { if (isAdvertising) { throw new IllegalStateException("HomeKit advertiser is already running"); @@ -49,11 +57,17 @@ public synchronized void advertise( this.setupId = setupId; this.category = category; this.configurationIndex = configurationIndex; + this.stateIndex = stateIndex; logger.trace("Advertising accessory " + label); registerService(); + if (isStarted) { + return; + } + this.isStarted = true; + Runtime.getRuntime() .addShutdownHook( new Thread( @@ -61,13 +75,16 @@ public synchronized void advertise( logger.trace("Stopping advertising in response to shutdown."); jmdns.unregisterAllServices(); })); - isAdvertising = true; } public synchronized void stop() { unregisterService(); } + public void setStateIndex(int stateIndex) { + this.stateIndex = stateIndex; + } + public synchronized void setDiscoverable(boolean discoverable) throws IOException { if (this.discoverable != discoverable) { this.discoverable = discoverable; @@ -102,20 +119,14 @@ public synchronized void setConfigurationIndex(int revision) throws IOException } private void unregisterService() { - if (serviceInfo != null) { - jmdns.unregisterService(serviceInfo); - serviceInfo = null; - } + jmdns.unregisterService(buildServiceInfo()); + isAdvertising = false; } private void registerService() throws IOException { logger.info("Registering " + SERVICE_TYPE + " on port " + port); - if (this.serviceInfo != null) { - throw new AssertionError( - "Registering an already registered service without unregistering first is not allowed"); - } - serviceInfo = buildServiceInfo(); - jmdns.registerService(serviceInfo); + jmdns.registerService(buildServiceInfo()); + isAdvertising = true; } private ServiceInfo buildServiceInfo() { @@ -126,7 +137,7 @@ private ServiceInfo buildServiceInfo() { props.put("md", label); props.put("sh", generateSHA512Hash(setupId + mac)); props.put("c#", Integer.toString(configurationIndex)); - props.put("s#", "1"); + props.put("s#", Integer.toString(stateIndex)); props.put("ff", "0"); props.put("ci", Integer.toString(category)); props.put("pv", "1.1"); diff --git a/src/main/java/io/github/hapjava/server/impl/json/AccessoryController.java b/src/main/java/io/github/hapjava/server/impl/json/AccessoryController.java index fdd223ec3..742bc65ca 100644 --- a/src/main/java/io/github/hapjava/server/impl/json/AccessoryController.java +++ b/src/main/java/io/github/hapjava/server/impl/json/AccessoryController.java @@ -31,7 +31,7 @@ public AccessoryController(HomekitRegistry registry) { public HttpResponse listing() throws Exception { JsonArrayBuilder accessories = Json.createArrayBuilder(); - Map>> accessoryServiceFutures = new HashMap<>(); + Map>> accessoryServiceFutures = new HashMap<>(); for (HomekitAccessory accessory : registry.getAccessories()) { List> serviceFutures = new ArrayList<>(); @@ -48,8 +48,8 @@ public HttpResponse listing() throws Exception { accessoryServiceFutures.put(accessory.getId(), serviceFutures); } - Map serviceArrayBuilders = new HashMap<>(); - for (Entry>> entry : + Map serviceArrayBuilders = new HashMap<>(); + for (Entry>> entry : accessoryServiceFutures.entrySet()) { JsonArrayBuilder arr = Json.createArrayBuilder(); for (CompletableFuture future : entry.getValue()) { diff --git a/src/main/java/io/github/hapjava/server/impl/json/CharacteristicsController.java b/src/main/java/io/github/hapjava/server/impl/json/CharacteristicsController.java index d061a11fc..f30b5ee34 100644 --- a/src/main/java/io/github/hapjava/server/impl/json/CharacteristicsController.java +++ b/src/main/java/io/github/hapjava/server/impl/json/CharacteristicsController.java @@ -39,7 +39,7 @@ public HttpResponse get(HttpRequest request) throws Exception { logger.warn("Unexpected characteristics request: " + uri); return new NotFoundResponse(); } - int aid = Integer.parseInt(parts[0]); + long aid = Long.parseLong(parts[0]); int iid = Integer.parseInt(parts[1]); JsonObjectBuilder characteristic = Json.createObjectBuilder(); Map characteristicMap = registry.getCharacteristics(aid); @@ -75,7 +75,7 @@ public HttpResponse put(HttpRequest request, HomekitClientConnection connection) Json.createReader(bais).readObject().getJsonArray("characteristics"); for (JsonValue value : jsonCharacteristics) { JsonObject jsonCharacteristic = (JsonObject) value; - int aid = jsonCharacteristic.getInt("aid"); + long aid = jsonCharacteristic.getJsonNumber("aid").longValue(); int iid = jsonCharacteristic.getInt("iid"); Map accessory = registry.getCharacteristics(aid); if (accessory.isEmpty()) { diff --git a/src/main/java/io/github/hapjava/server/impl/json/EventController.java b/src/main/java/io/github/hapjava/server/impl/json/EventController.java index 0c7c2bc7c..2f99a6ae9 100644 --- a/src/main/java/io/github/hapjava/server/impl/json/EventController.java +++ b/src/main/java/io/github/hapjava/server/impl/json/EventController.java @@ -13,7 +13,7 @@ public class EventController { - public HttpResponse getMessage(int accessoryId, int iid, EventableCharacteristic changed) + public HttpResponse getMessage(long accessoryId, long iid, EventableCharacteristic changed) throws Exception { JsonArrayBuilder characteristics = Json.createArrayBuilder(); diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/ByteUtils.java b/src/main/java/io/github/hapjava/server/impl/pairing/ByteUtils.java index 6516e2e29..e65beec3c 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/ByteUtils.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/ByteUtils.java @@ -22,7 +22,7 @@ public static byte[] joinBytes(byte[]... piece) { return ret; } - public static byte[] toByteArray(BigInteger i) { + public static byte[] toUnsignedByteArray(BigInteger i) { byte[] array = i.toByteArray(); if (array[0] == 0) { array = Arrays.copyOfRange(array, 1, array.length); diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/ClientEvidenceRoutineImpl.java b/src/main/java/io/github/hapjava/server/impl/pairing/ClientEvidenceRoutineImpl.java index 16c514707..87ddf3907 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/ClientEvidenceRoutineImpl.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/ClientEvidenceRoutineImpl.java @@ -8,9 +8,7 @@ class ClientEvidenceRoutineImpl implements ClientEvidenceRoutine { - public ClientEvidenceRoutineImpl() { - // TODO Auto-generated constructor stub - } + public ClientEvidenceRoutineImpl() {} /** * Calculates M1 according to the following formula: @@ -27,10 +25,10 @@ public BigInteger computeClientEvidence( } catch (NoSuchAlgorithmException e) { throw new RuntimeException("Could not locate requested algorithm", e); } - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(cryptoParams.N)); + digest.update(BigIntegerUtils.bigIntegerToBytes(cryptoParams.N)); byte[] hN = digest.digest(); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(cryptoParams.g)); + digest.update(BigIntegerUtils.bigIntegerToBytes(cryptoParams.g)); byte[] hg = digest.digest(); byte[] hNhg = xor(hN, hg); @@ -38,14 +36,14 @@ public BigInteger computeClientEvidence( digest.update(ctx.userID.getBytes(StandardCharsets.UTF_8)); byte[] hu = digest.digest(); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.S)); + digest.update(BigIntegerUtils.bigIntegerToBytes(ctx.S)); byte[] hS = digest.digest(); digest.update(hNhg); digest.update(hu); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.s)); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.A)); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.B)); + digest.update(BigIntegerUtils.bigIntegerToBytes(ctx.s)); + digest.update(BigIntegerUtils.bigIntegerToBytes(ctx.A)); + digest.update(BigIntegerUtils.bigIntegerToBytes(ctx.B)); digest.update(hS); BigInteger ret = new BigInteger(1, digest.digest()); return ret; diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/HomekitSRP6ServerSession.java b/src/main/java/io/github/hapjava/server/impl/pairing/HomekitSRP6ServerSession.java index 3841d9fb7..116fced13 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/HomekitSRP6ServerSession.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/HomekitSRP6ServerSession.java @@ -8,6 +8,7 @@ import com.nimbusds.srp6.SRP6Session; import com.nimbusds.srp6.URoutineContext; import java.math.BigInteger; +import java.security.MessageDigest; /** * This is a slightly modified version of the SRP6ServerSession class included with nimbus. The only @@ -74,6 +75,8 @@ public static enum State { /** The current SRP-6a auth state. */ private State state; + private MessageDigest digest; + /** * Creates a new server-side SRP-6a authentication session and sets its state to {@link * State#INIT}. @@ -92,7 +95,7 @@ public HomekitSRP6ServerSession(final SRP6CryptoParams config, final int timeout this.config = config; - digest = config.getMessageDigestInstance(); + this.digest = config.getMessageDigestInstance(); if (digest == null) throw new IllegalArgumentException("Unsupported hash algorithm 'H': " + config.H); @@ -151,13 +154,13 @@ public BigInteger step1(final String userID, final BigInteger s, final BigIntege throw new IllegalStateException("State violation: Session must be in INIT state"); // Generate server private and public values - k = SRP6Routines.computeK(digest, config.N, config.g); + k = new SRP6Routines().computeK(digest, config.N, config.g); digest.reset(); b = HomekitSRP6Routines.generatePrivateValue(config.N, random); digest.reset(); - B = SRP6Routines.computePublicServerValue(config.N, config.g, k, v, b); + B = new SRP6Routines().computePublicServerValue(config.N, config.g, k, v, b); state = State.STEP_1; @@ -234,7 +237,7 @@ public BigInteger step2(final BigInteger A, final BigInteger M1) throws SRP6Exce if (hasTimedOut()) throw new SRP6Exception("Session timeout", SRP6Exception.CauseType.TIMEOUT); // Check A validity - if (!SRP6Routines.isValidPublicValue(config.N, A)) + if (!new SRP6Routines().isValidPublicValue(config.N, A)) throw new SRP6Exception( "Bad client public value 'A'", SRP6Exception.CauseType.BAD_PUBLIC_VALUE); @@ -246,11 +249,11 @@ public BigInteger step2(final BigInteger A, final BigInteger M1) throws SRP6Exce URoutineContext hashedKeysContext = new URoutineContext(A, B); u = hashedKeysRoutine.computeU(config, hashedKeysContext); } else { - u = SRP6Routines.computeU(digest, config.N, A, B); + u = new SRP6Routines().computeU(digest, config.N, A, B); digest.reset(); } - S = SRP6Routines.computeSessionKey(config.N, v, u, A, b); + S = new SRP6Routines().computeSessionKey(config.N, v, u, A, b); // Compute the own client evidence message 'M1' BigInteger computedM1; @@ -262,7 +265,7 @@ public BigInteger step2(final BigInteger A, final BigInteger M1) throws SRP6Exce computedM1 = clientEvidenceRoutine.computeClientEvidence(config, ctx); } else { // With default routine - computedM1 = SRP6Routines.computeClientEvidence(digest, A, B, S); + computedM1 = new SRP6Routines().computeClientEvidence(digest, A, B, S); digest.reset(); } diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/PairVerifyManager.java b/src/main/java/io/github/hapjava/server/impl/pairing/PairVerifyManager.java index 44f25c6d1..5042132b3 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/PairVerifyManager.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/PairVerifyManager.java @@ -14,6 +14,7 @@ import io.github.hapjava.server.impl.pairing.TypeLengthValueUtils.DecodeResult; import io.github.hapjava.server.impl.pairing.TypeLengthValueUtils.Encoder; import io.github.hapjava.server.impl.responses.NotFoundResponse; +import io.github.hapjava.server.impl.responses.OkResponse; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import org.bouncycastle.crypto.digests.SHA512Digest; @@ -114,8 +115,13 @@ private HttpResponse handleVerifyFinishRequest(VerifyFinishRequest request) thro } Encoder encoder = TypeLengthValueUtils.getEncoder(); + encoder.add(MessageType.STATE, (short) 4); + if (clientLtpk == null) { + logger.error("Unknown user: {}", new String(clientUsername, StandardCharsets.UTF_8)); + return new OkResponse(encoder.toByteArray()); + } + if (new EdsaVerifier(clientLtpk).verify(material, clientSignature)) { - encoder.add(MessageType.STATE, (short) 4); logger.trace("Completed pair verification for " + registry.getLabel()); return new UpgradeResponse( encoder.toByteArray(), diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/ServerEvidenceRoutineImpl.java b/src/main/java/io/github/hapjava/server/impl/pairing/ServerEvidenceRoutineImpl.java index 7cf7b3164..6c032ce59 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/ServerEvidenceRoutineImpl.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/ServerEvidenceRoutineImpl.java @@ -1,5 +1,6 @@ package io.github.hapjava.server.impl.pairing; +import com.nimbusds.srp6.BigIntegerUtils; import com.nimbusds.srp6.SRP6CryptoParams; import com.nimbusds.srp6.SRP6ServerEvidenceContext; import com.nimbusds.srp6.ServerEvidenceRoutine; @@ -20,10 +21,10 @@ public BigInteger computeServerEvidence( throw new RuntimeException("Could not locate requested algorithm", e); } - byte[] hS = digest.digest(SrpHandler.bigIntegerToUnsignedByteArray(ctx.S)); + byte[] hS = digest.digest(BigIntegerUtils.bigIntegerToBytes(ctx.S)); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.A)); - digest.update(SrpHandler.bigIntegerToUnsignedByteArray(ctx.M1)); + digest.update(BigIntegerUtils.bigIntegerToBytes(ctx.A)); + digest.update(BigIntegerUtils.bigIntegerToBytes(ctx.M1)); digest.update(hS); return new BigInteger(1, digest.digest()); diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/SrpHandler.java b/src/main/java/io/github/hapjava/server/impl/pairing/SrpHandler.java index 5c1c23353..334d44f7f 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/SrpHandler.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/SrpHandler.java @@ -82,7 +82,7 @@ private HttpResponse handleSrpVerifyRequest(SRPVerifyRequest request) throws Exc public byte[] getK() { MessageDigest digest = session.getCryptoParams().getMessageDigestInstance(); - BigInteger S = session.getSessionKey(false); + BigInteger S = session.getSessionKey(); byte[] sBytes = bigIntegerToUnsignedByteArray(S); return digest.digest(sBytes); } diff --git a/src/main/java/io/github/hapjava/server/impl/pairing/TypeLengthValueUtils.java b/src/main/java/io/github/hapjava/server/impl/pairing/TypeLengthValueUtils.java index cbd76f118..0f2e8efac 100644 --- a/src/main/java/io/github/hapjava/server/impl/pairing/TypeLengthValueUtils.java +++ b/src/main/java/io/github/hapjava/server/impl/pairing/TypeLengthValueUtils.java @@ -1,5 +1,6 @@ package io.github.hapjava.server.impl.pairing; +import com.nimbusds.srp6.BigIntegerUtils; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -45,7 +46,7 @@ public void add(MessageType type) { } public void add(MessageType type, BigInteger i) throws IOException { - add(type, ByteUtils.toByteArray(i)); + add(type, BigIntegerUtils.bigIntegerToBytes(i)); } public void add(MessageType type, short b) { diff --git a/src/main/java/io/github/hapjava/services/impl/ProtocolInformationService.java b/src/main/java/io/github/hapjava/services/impl/ProtocolInformationService.java new file mode 100644 index 000000000..2be2f346b --- /dev/null +++ b/src/main/java/io/github/hapjava/services/impl/ProtocolInformationService.java @@ -0,0 +1,20 @@ +package io.github.hapjava.services.impl; + +import static io.github.hapjava.server.impl.HomekitServer.PROTOCOL_VERSION; + +import io.github.hapjava.accessories.HomekitAccessory; +import io.github.hapjava.characteristics.impl.common.VersionCharacteristic; +import java.util.concurrent.CompletableFuture; + +/** Accessory Information service. */ +public class ProtocolInformationService extends AbstractServiceImpl { + + public ProtocolInformationService(VersionCharacteristic version) { + super("000000A2‐0000‐1000‐8000‐0026BB765291"); + addCharacteristic(version); + } + + public ProtocolInformationService(HomekitAccessory accessory) { + this(new VersionCharacteristic(() -> CompletableFuture.completedFuture(PROTOCOL_VERSION))); + } +} diff --git a/src/test/java/io/github/hapjava/server/impl/HomekitRootTest.java b/src/test/java/io/github/hapjava/server/impl/HomekitRootTest.java index 81d2666e5..2c93e9fd9 100644 --- a/src/test/java/io/github/hapjava/server/impl/HomekitRootTest.java +++ b/src/test/java/io/github/hapjava/server/impl/HomekitRootTest.java @@ -1,5 +1,8 @@ package io.github.hapjava.server.impl; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; @@ -14,9 +17,8 @@ import io.github.hapjava.server.impl.http.HomekitClientConnectionFactory; import io.github.hapjava.server.impl.jmdns.JmdnsHomekitAdvertiser; import java.util.concurrent.CompletableFuture; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class HomekitRootTest { @@ -31,10 +33,10 @@ public class HomekitRootTest { private static final String LABEL = "Test Label"; - @Before + @BeforeEach public void setup() throws Exception { accessory = mock(HomekitAccessory.class); - when(accessory.getId()).thenReturn(2); + when(accessory.getId()).thenReturn(2l); webHandler = mock(HomekitWebHandler.class); when(webHandler.start(any())).thenReturn(CompletableFuture.completedFuture(PORT)); advertiser = mock(JmdnsHomekitAdvertiser.class); @@ -46,18 +48,18 @@ public void setup() throws Exception { @Test public void verifyRegistryAdded() throws Exception { root.addAccessory(accessory); - Assert.assertTrue( - "Registry does not contain accessory", - root.getRegistry().getAccessories().contains(accessory)); + assertTrue( + root.getRegistry().getAccessories().contains(accessory), + "Registry does not contain accessory"); } @Test public void verifyRegistryRemoved() throws Exception { root.addAccessory(accessory); root.removeAccessory(accessory); - Assert.assertFalse( - "Registry still contains accessory", - root.getRegistry().getAccessories().contains(accessory)); + assertFalse( + root.getRegistry().getAccessories().contains(accessory), + "Registry still contains accessory"); } @Test @@ -80,7 +82,7 @@ public void testAdvertiserStarts() throws Exception { when(authInfo.getSetupId()).thenReturn(SETUPID); root.start(); - verify(advertiser).advertise(eq(LABEL), eq(1), eq(mac), eq(PORT), eq(1), eq(SETUPID)); + verify(advertiser).advertise(eq(LABEL), eq(1), eq(mac), eq(PORT), eq(1), eq(SETUPID), eq(1)); } @Test @@ -105,9 +107,13 @@ public void testRemoveAccessoryDoesntResetWeb() { verify(webHandler, never()).resetConnections(); } - @Test(expected = IndexOutOfBoundsException.class) + @Test public void testAddIndexOneAccessory() throws Exception { - when(accessory.getId()).thenReturn(1); - root.addAccessory(accessory); + assertThrows( + IndexOutOfBoundsException.class, + () -> { + when(accessory.getId()).thenReturn(1l); + root.addAccessory(accessory); + }); } } diff --git a/src/test/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiserTest.java b/src/test/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiserTest.java index 870bd739b..c58b37782 100644 --- a/src/test/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiserTest.java +++ b/src/test/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiserTest.java @@ -9,8 +9,8 @@ import java.net.UnknownHostException; import javax.jmdns.JmDNS; import javax.jmdns.ServiceInfo; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; public class JmdnsHomekitAdvertiserTest { @@ -18,7 +18,7 @@ public class JmdnsHomekitAdvertiserTest { JmdnsHomekitAdvertiser subject; JmDNS jmdns; - @Before + @BeforeEach public void setup() throws UnknownHostException, IOException { jmdns = mock(JmDNS.class); subject = new JmdnsHomekitAdvertiser(jmdns); @@ -39,7 +39,7 @@ public void testSetDiscoverableAfterAdvertise() throws Exception { subject.setDiscoverable(false); advertise(); subject.setDiscoverable(true); - assertThat(getArgumentFromUnregister().getPropertyString("sf")).isEqualTo("0"); + assertThat(getArgumentFromUnregister().getPropertyString("sf")).isEqualTo("1"); } /* @@ -51,7 +51,7 @@ public void testSetConfigurationIndex() throws Exception { subject.setConfigurationIndex(1); advertise(); subject.setConfigurationIndex(2); - assertThat(getArgumentFromUnregister().getPropertyString("c#")).isEqualTo("1"); + assertThat(getArgumentFromUnregister().getPropertyString("c#")).isEqualTo("2"); } private ServiceInfo getArgumentFromUnregister() { @@ -61,6 +61,6 @@ private ServiceInfo getArgumentFromUnregister() { } private void advertise() throws Exception { - subject.advertise("test", 1, "00:00:00:00:00:00", 1234, 1, "1"); + subject.advertise("test", 1, "00:00:00:00:00:00", 1234, 1, "1", 1); } }