Skip to content

Commit

Permalink
Extract implementations.
Browse files Browse the repository at this point in the history
  • Loading branch information
dkocher committed Sep 6, 2024
1 parent 8843c95 commit c14d49c
Show file tree
Hide file tree
Showing 6 changed files with 219 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import ch.cyberduck.core.Local;
import ch.cyberduck.core.preferences.PreferencesFactory;
import ch.cyberduck.core.socket.IOKitHardwareAddress;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -50,10 +51,6 @@
import java.util.Collection;
import java.util.Enumeration;

import com.sun.jna.platform.mac.CoreFoundation;
import com.sun.jna.platform.mac.IOKit;
import com.sun.jna.platform.mac.IOKitUtil;

public class ReceiptVerifier implements LicenseVerifier {
private static final Logger log = LogManager.getLogger(ReceiptVerifier.class);

Expand Down Expand Up @@ -155,57 +152,35 @@ else if(((ASN1Integer) type).getValue().intValue() == 5) {
if(!StringUtils.equals(version, StringUtils.trim(bundleVersion))) {
log.warn(String.format("Bundle version %s in ASN set does not match", bundleVersion));
}
final IOKit.IOService en0 = IOKitUtil.getMatchingService(IOKitUtil.getBSDNameMatchingDict("en0"));
if(null == en0) {
// Interface is not found when link is down #fail
log.warn("No network interface en0");
final byte[] address = new IOKitHardwareAddress().getAddress();
final String hex = Hex.encodeHexString(address);
if(log.isDebugEnabled()) {
log.debug(String.format("Interface en0 %s", hex));
}
// Compute the hash of the GUID
final MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(address);
if(null == opaque) {
log.error(String.format("Missing opaque string in ASN.1 set %s", asn));
return false;
}
digest.update(opaque);
if(null == bundleIdentifier) {
log.error(String.format("Missing bundle identifier in ASN.1 set %s", asn));
return false;
}
digest.update(bundleIdentifier.getBytes(StandardCharsets.UTF_8));
final byte[] result = digest.digest();
if(Arrays.equals(result, hash)) {
if(log.isInfoEnabled()) {
log.info(String.format("Valid receipt for GUID %s", hex));
}
guid = hex;
return true;
}
else {
// #define kIOMACAddress "IOMACAddress"
final CoreFoundation.CFStringRef kIOMACAddress = CoreFoundation.CFStringRef.createCFString("IOMACAddress");
// #define kIOServicePlane "IOService"
final String kIOServicePlane = "IOService";
int kIORegistryIterateRecursively = 0x00000001;
int kIORegistryIterateParents = 0x00000002;
final CoreFoundation.CFTypeRef property = IOKit.INSTANCE.IORegistryEntrySearchCFProperty(en0, kIOServicePlane, kIOMACAddress,
CoreFoundation.INSTANCE.CFAllocatorGetDefault(), kIORegistryIterateRecursively | kIORegistryIterateParents);
if(null == property) {
log.error("Cannot determine MAC address");
// Continue without validation
return true;
}
final CoreFoundation.CFDataRef dataRef = new CoreFoundation.CFDataRef(property.getPointer());
final byte[] mac = dataRef.getBytePtr().getByteArray(0, dataRef.getLength());
final String hex = Hex.encodeHexString(mac);
if(log.isDebugEnabled()) {
log.debug(String.format("Interface en0 %s", hex));
}
// Compute the hash of the GUID
final MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(mac);
if(null == opaque) {
log.error(String.format("Missing opaque string in ASN.1 set %s", asn));
return false;
}
digest.update(opaque);
if(null == bundleIdentifier) {
log.error(String.format("Missing bundle identifier in ASN.1 set %s", asn));
return false;
}
digest.update(bundleIdentifier.getBytes(StandardCharsets.UTF_8));
final byte[] result = digest.digest();
if(Arrays.equals(result, hash)) {
if(log.isInfoEnabled()) {
log.info(String.format("Valid receipt for GUID %s", hex));
}
guid = hex;
return true;
}
else {
log.error(String.format("Failed verification. Hash with GUID %s does not match hash in receipt", hex));
return false;
}
log.error(String.format("Failed verification. Hash with GUID %s does not match hash in receipt", hex));
return false;
}
}
catch(IOException | GeneralSecurityException | CMSException | SecurityException e) {
Expand Down
23 changes: 23 additions & 0 deletions core/src/main/java/ch/cyberduck/core/socket/HardwareAddress.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ch.cyberduck.core.socket;

/*
* Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
* https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

import ch.cyberduck.core.exception.BackgroundException;

public interface HardwareAddress {

byte[] getAddress() throws BackgroundException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package ch.cyberduck.core.socket;

/*
* Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
* https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.exception.UnsupportedException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.sun.jna.platform.mac.CoreFoundation;
import com.sun.jna.platform.mac.IOKit;
import com.sun.jna.platform.mac.IOKitUtil;

public class IOKitHardwareAddress implements HardwareAddress {
private static final Logger log = LogManager.getLogger(IOKitHardwareAddress.class);

// #define kIOMACAddress "IOMACAddress"
private static final CoreFoundation.CFStringRef kIOMACAddress = CoreFoundation.CFStringRef.createCFString("IOMACAddress");
// #define kIOServicePlane "IOService"
private final String kIOServicePlane = "IOService";

private final int kIORegistryIterateRecursively = 0x00000001;
private final int kIORegistryIterateParents = 0x00000002;

@Override
public byte[] getAddress() throws BackgroundException {
final IOKit.IOService en0 = IOKitUtil.getMatchingService(IOKitUtil.getBSDNameMatchingDict("en0"));
if(null == en0) {
// Interface is not found when link is down #fail
log.warn("No network interface en0");
throw new UnsupportedException("No network interface en0");
}
final CoreFoundation.CFTypeRef property = IOKit.INSTANCE.IORegistryEntrySearchCFProperty(en0, kIOServicePlane, kIOMACAddress,
CoreFoundation.INSTANCE.CFAllocatorGetDefault(), kIORegistryIterateRecursively | kIORegistryIterateParents);
if(null == property) {
log.error("Cannot determine MAC address");
throw new UnsupportedException("No hardware address for network interface en0");
}
final CoreFoundation.CFDataRef dataRef = new CoreFoundation.CFDataRef(property.getPointer());
return dataRef.getBytePtr().getByteArray(0, dataRef.getLength());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package ch.cyberduck.core.socket;

/*
* Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
* https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

import ch.cyberduck.core.DefaultIOExceptionMappingService;
import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.exception.UnsupportedException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.net.NetworkInterface;
import java.net.SocketException;

public class NetworkInterfaceHardwareAddress implements HardwareAddress {
private static final Logger log = LogManager.getLogger(NetworkInterfaceHardwareAddress.class);

@Override
public byte[] getAddress() throws BackgroundException {
try {
final NetworkInterface en0 = NetworkInterface.getByName("en0");
if(null == en0) {
// Interface is not found when link is down #fail
log.warn("No network interface en0");
throw new UnsupportedException("No network interface en0");
}
final byte[] address = en0.getHardwareAddress();
if(null == address) {
log.error("Cannot determine MAC address");
throw new UnsupportedException("No hardware address for network interface en0");
}
return address;
}
catch(SocketException e) {
throw new DefaultIOExceptionMappingService().map(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ch.cyberduck.core.socket;

/*
* Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
* https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class IOKitHardwareAddressTest {

@Test
public void getAddress() throws Exception {
final byte[] address = new IOKitHardwareAddress().getAddress();
assertNotNull(address);
assertEquals(6, address.length);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ch.cyberduck.core.socket;

/*
* Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
* https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class NetworkInterfaceHardwareAddressTest {

@Test
public void getAddress() throws Exception {
final byte[] address = new NetworkInterfaceHardwareAddress().getAddress();
assertNotNull(address);
assertEquals(6, address.length);
}
}

0 comments on commit c14d49c

Please sign in to comment.