// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/ios/device_util.h"

#include <CommonCrypto/CommonDigest.h>
#import <UIKit/UIKit.h>
#include <ifaddrs.h>
#include <net/if_dl.h>
#include <stddef.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/sysctl.h>

#include <memory>

#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"

namespace {

// Client ID key in the user preferences.
NSString* const kLegacyClientIdPreferenceKey = @"ChromiumClientID";
NSString* const kClientIdPreferenceKey = @"ChromeClientID";
// Current hardware type. This is used to detect that a device has been backed
// up and restored to another device, and allows regenerating a new device id.
NSString* const kHardwareTypePreferenceKey = @"ClientIDGenerationHardwareType";
// Default salt for device ids.
const char kDefaultSalt[] = "Salt";
// Zero UUID returned on buggy iOS devices.
NSString* const kZeroUUID = @"00000000-0000-0000-0000-000000000000";

NSString* GenerateClientId() {
  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

  // Try to migrate from legacy client id.
  NSString* client_id = [defaults stringForKey:kLegacyClientIdPreferenceKey];

  // Some iOS6 devices return a buggy identifierForVendor:
  // http://openradar.appspot.com/12377282. If this is the case, revert to
  // generating a new one.
  if (!client_id || [client_id isEqualToString:kZeroUUID]) {
    client_id = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    if ([client_id isEqualToString:kZeroUUID])
      client_id = base::SysUTF8ToNSString(ios::device_util::GetRandomId());
  }
  return client_id;
}

}  // namespace

namespace ios {
namespace device_util {

std::string GetPlatform() {
  std::string platform;
  size_t size = 0;
  sysctlbyname("hw.machine", NULL, &size, NULL, 0);
  sysctlbyname("hw.machine", base::WriteInto(&platform, size), &size, NULL, 0);
  return platform;
}

bool RamIsAtLeast512Mb() {
  // 512MB devices report anywhere from 502-504 MB, use 450 MB just to be safe.
  return RamIsAtLeast(450);
}

bool RamIsAtLeast1024Mb() {
  // 1GB devices report anywhere from 975-999 MB, use 900 MB just to be safe.
  return RamIsAtLeast(900);
}

bool RamIsAtLeast(uint64_t ram_in_mb) {
  uint64_t memory_size = 0;
  size_t size = sizeof(memory_size);
  if (sysctlbyname("hw.memsize", &memory_size, &size, NULL, 0) == 0) {
    // Anything >= 500M, call high ram.
    return memory_size >= ram_in_mb * 1024 * 1024;
  }
  return false;
}

bool IsSingleCoreDevice() {
  uint64_t cpu_number = 0;
  size_t sizes = sizeof(cpu_number);
  sysctlbyname("hw.physicalcpu", &cpu_number, &sizes, NULL, 0);
  return cpu_number == 1;
}

std::string GetMacAddress(const std::string& interface_name) {
  std::string mac_string;
  struct ifaddrs* addresses;
  if (getifaddrs(&addresses) == 0) {
    for (struct ifaddrs* address = addresses; address;
         address = address->ifa_next) {
      if ((address->ifa_addr->sa_family == AF_LINK) &&
          strcmp(interface_name.c_str(), address->ifa_name) == 0) {
        const struct sockaddr_dl* found_address_struct =
            reinterpret_cast<const struct sockaddr_dl*>(address->ifa_addr);

        // |found_address_struct->sdl_data| contains the interface name followed
        // by the interface address. The address part can be accessed based on
        // the length of the name, that is, |found_address_struct->sdl_nlen|.
        const unsigned char* found_address =
            reinterpret_cast<const unsigned char*>(
                &found_address_struct->sdl_data[
                    found_address_struct->sdl_nlen]);

        int found_address_length = found_address_struct->sdl_alen;
        for (int i = 0; i < found_address_length; ++i) {
          if (i != 0)
            mac_string.push_back(':');
          base::StringAppendF(&mac_string, "%02X", found_address[i]);
        }
        break;
      }
    }
    freeifaddrs(addresses);
  }
  return mac_string;
}

std::string GetRandomId() {
  base::ScopedCFTypeRef<CFUUIDRef> uuid_object(
      CFUUIDCreate(kCFAllocatorDefault));
  base::ScopedCFTypeRef<CFStringRef> uuid_string(
      CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
  return base::SysCFStringRefToUTF8(uuid_string);
}

std::string GetDeviceIdentifier(const char* salt) {
  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

  NSString* last_seen_hardware =
      [defaults stringForKey:kHardwareTypePreferenceKey];
  NSString* current_hardware = base::SysUTF8ToNSString(GetPlatform());
  if (!last_seen_hardware) {
    last_seen_hardware = current_hardware;
    [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey];
    [defaults synchronize];
  }

  NSString* client_id = [defaults stringForKey:kClientIdPreferenceKey];

  if (!client_id || ![last_seen_hardware isEqualToString:current_hardware]) {
    client_id = GenerateClientId();
    [defaults setObject:client_id forKey:kClientIdPreferenceKey];
    [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey];
    [defaults synchronize];
  }

  return GetSaltedString(base::SysNSStringToUTF8(client_id),
                         salt ? salt : kDefaultSalt);
}

std::string GetSaltedString(const std::string& in_string,
                            const std::string& salt) {
  DCHECK(salt.length());
  NSData* hash_data = [base::SysUTF8ToNSString(in_string + salt)
      dataUsingEncoding:NSUTF8StringEncoding];

  unsigned char hash[CC_SHA256_DIGEST_LENGTH];
  CC_SHA256([hash_data bytes], [hash_data length], hash);
  CFUUIDBytes* uuid_bytes = reinterpret_cast<CFUUIDBytes*>(hash);

  base::ScopedCFTypeRef<CFUUIDRef> uuid_object(
      CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, *uuid_bytes));
  base::ScopedCFTypeRef<CFStringRef> device_id(
      CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
  return base::SysCFStringRefToUTF8(device_id);
}

}  // namespace device_util
}  // namespace ios
