<commit_before>// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.internal.statistic;

import com.intellij.internal.statistic.utils.PluginInfoDetectorKt;
import com.intellij.openapi.application.ex.ApplicationInfoEx;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.UUID;
import java.util.prefs.Preferences;

public final class DeviceIdManager {
  private static final Logger LOG = Logger.getInstance(DeviceIdManager.class);

  private static final String UNDEFINED = "UNDEFINED";
  private static final String DEVICE_ID_SHARED_FILE = "PermanentDeviceId";
  private static final String DEVICE_ID_PREFERENCE_KEY = "device_id";

  /**
   * @deprecated Use getOrGenerateId(String) with purpose specific id
   */
  @Deprecated
  public static String getOrGenerateId() {
    try {
      return getOrGenerateId(null, UNDEFINED);
    }
    catch (InvalidDeviceIdTokenException e) {
      LOG.error(e);
    }
    return "";
  }

  public static String getOrGenerateId(@Nullable DeviceIdToken token, @NotNull String recorderId) throws InvalidDeviceIdTokenException {
    assertAllowed(token, recorderId);

    ApplicationInfoEx appInfo = ApplicationInfoImpl.getShadowInstance();
    Preferences prefs = getPreferences(appInfo);

    String preferenceKey = getPreferenceKey(recorderId);
    String deviceId = prefs.get(preferenceKey, null);
    if (StringUtil.isEmptyOrSpaces(deviceId)) {
      deviceId = generateId(Calendar.getInstance(Locale.ENGLISH), getOSChar());
      prefs.put(preferenceKey, deviceId);
      LOG.info("Generating new Device ID for '" + recorderId + "'");
    }

    if (appInfo.isVendorJetBrains() && SystemInfo.isWindows) {
      if (isBaseRecorder(recorderId)) {
        deviceId = syncWithSharedFile(DEVICE_ID_SHARED_FILE, deviceId, prefs, preferenceKey);
      }
      else {
        deleteLegacySharedFile(recorderId + "_" + DEVICE_ID_SHARED_FILE);
      }
    }
    return deviceId;
  }

  private static void assertAllowed(@Nullable DeviceIdToken token, @NotNull String recorderId) throws InvalidDeviceIdTokenException {
    LOG.info("Access device id for '" + recorderId + "' from " + (token == null ? "unknown" : token.getClass().getName()));

    if (isBaseRecorder(recorderId)) {
      if (token == null) {
        throw new InvalidDeviceIdTokenException("Cannot access base device id from unknown class");
      }
      else if (!PluginInfoDetectorKt.getPluginInfo(token.getClass()).getType().isPlatformOrJetBrainsBundled()) {
        throw new InvalidDeviceIdTokenException("Cannot access base device id from " + token.getClass().getName());
      }
    }
    else if (!isUndefinedRecorder(recorderId)) {
      if (token == null) {
        throw new InvalidDeviceIdTokenException("Cannot access device id from unknown class");
      }
    }
  }

  @NotNull
  private static String getPreferenceKey(@NotNull String recorderId) {
    return isBaseRecorder(recorderId) ? DEVICE_ID_PREFERENCE_KEY : StringUtil.toLowerCase(recorderId) + "_" + DEVICE_ID_PREFERENCE_KEY;
  }

  private static boolean isBaseRecorder(@NotNull String recorderId) {
    return "FUS".equals(recorderId);
  }

  private static boolean isUndefinedRecorder(@NotNull String recorderId) {
    return UNDEFINED.equals(recorderId);
  }

  @SuppressWarnings("SameParameterValue")
  @NotNull
  private static String syncWithSharedFile(@NotNull String fileName,<commit_msg>FUS: IDEA-263277 remove logging access to device id<commit_after>// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.internal.statistic;

import com.intellij.internal.statistic.utils.PluginInfoDetectorKt;
import com.intellij.openapi.application.ex.ApplicationInfoEx;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.UUID;
import java.util.prefs.Preferences;

public final class DeviceIdManager {
  private static final Logger LOG = Logger.getInstance(DeviceIdManager.class);

  private static final String UNDEFINED = "UNDEFINED";
  private static final String DEVICE_ID_SHARED_FILE = "PermanentDeviceId";
  private static final String DEVICE_ID_PREFERENCE_KEY = "device_id";

  /**
   * @deprecated Use getOrGenerateId(String) with purpose specific id
   */
  @Deprecated
  public static String getOrGenerateId() {
    try {
      return getOrGenerateId(null, UNDEFINED);
    }
    catch (InvalidDeviceIdTokenException e) {
      LOG.error(e);
    }
    return "";
  }

  public static String getOrGenerateId(@Nullable DeviceIdToken token, @NotNull String recorderId) throws InvalidDeviceIdTokenException {
    assertAllowed(token, recorderId);

    ApplicationInfoEx appInfo = ApplicationInfoImpl.getShadowInstance();
    Preferences prefs = getPreferences(appInfo);

    String preferenceKey = getPreferenceKey(recorderId);
    String deviceId = prefs.get(preferenceKey, null);
    if (StringUtil.isEmptyOrSpaces(deviceId)) {
      deviceId = generateId(Calendar.getInstance(Locale.ENGLISH), getOSChar());
      prefs.put(preferenceKey, deviceId);
      LOG.info("Generating new Device ID for '" + recorderId + "'");
    }

    if (appInfo.isVendorJetBrains() && SystemInfo.isWindows) {
      if (isBaseRecorder(recorderId)) {
        deviceId = syncWithSharedFile(DEVICE_ID_SHARED_FILE, deviceId, prefs, preferenceKey);
      }
      else {
        deleteLegacySharedFile(recorderId + "_" + DEVICE_ID_SHARED_FILE);
      }
    }
    return deviceId;
  }

  private static void assertAllowed(@Nullable DeviceIdToken token, @NotNull String recorderId) throws InvalidDeviceIdTokenException {
    if (isBaseRecorder(recorderId)) {
      if (token == null) {
        throw new InvalidDeviceIdTokenException("Cannot access base device id from unknown class");
      }
      else if (!PluginInfoDetectorKt.getPluginInfo(token.getClass()).getType().isPlatformOrJetBrainsBundled()) {
        throw new InvalidDeviceIdTokenException("Cannot access base device id from " + token.getClass().getName());
      }
    }
    else if (!isUndefinedRecorder(recorderId)) {
      if (token == null) {
        throw new InvalidDeviceIdTokenException("Cannot access device id from unknown class");
      }
    }
  }

  @NotNull
  private static String getPreferenceKey(@NotNull String recorderId) {
    return isBaseRecorder(recorderId) ? DEVICE_ID_PREFERENCE_KEY : StringUtil.toLowerCase(recorderId) + "_" + DEVICE_ID_PREFERENCE_KEY;
  }

  private static boolean isBaseRecorder(@NotNull String recorderId) {
    return "FUS".equals(recorderId);
  }

  private static boolean isUndefinedRecorder(@NotNull String recorderId) {
    return UNDEFINED.equals(recorderId);
  }

  @SuppressWarnings("SameParameterValue")
  @NotNull
  private static String syncWithSharedFile(@NotNull String fileName,
{'fraction_non_alphanumeric': 0.09467530817130512, 'fraction_numerical': 0.003304104714703266, 'mean_word_length': 4.534458509142054, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3405541', 'n_tokens_mistral': 2345, 'n_tokens_neox': 2287, 'n_words': 522}