text: // Copyright 2019 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.
  
  #ifndef CHROME_BROWSER_ASH_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_AUTHENTICATOR_H_
  #define CHROME_BROWSER_ASH_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_AUTHENTICATOR_H_
  
  #include <memory>
  #include <ostream>
  #include <string>
  
  #include "base/macros.h"
  #include "base/time/time.h"
  #include "components/account_id/account_id.h"
  #include "crypto/hmac.h"
  #include "third_party/abseil-cpp/absl/types/optional.h"
  
  namespace base {
  class DictionaryValue;
  class Value;
  }  // namespace base
  
  namespace ash {
  namespace parent_access {
  
  // Configuration used to generate and verify parent access code.
  class AccessCodeConfig {
   public:
    // Returns AccessCodeConfig created from a |dictionary|, if the |dictionary|
    // contains valid config data.
    static absl::optional<AccessCodeConfig> FromDictionary(
        const base::DictionaryValue& value);
  
    // TODO(agawronska): Make constructor private.
    // To create valid AccessCodeConfig:
    // * |shared_secret| cannot be empty
    // * |code_validity| needs to be in between 30s and 3600s
    // * |clock_drift_tolerance| needs to be between 0 and 1800s
    // The above restrictions are applied to AccessCodeConfig policy that is the
    // main source of this configuration.
    AccessCodeConfig(const std::string& shared_secret,
                     base::TimeDelta code_validity,
                     base::TimeDelta clock_drift_tolerance);
    AccessCodeConfig(AccessCodeConfig&&);
    AccessCodeConfig& operator=(AccessCodeConfig&&);
    ~AccessCodeConfig();
  
    // Secret shared between child and parent devices.
    const std::string& shared_secret() const { return shared_secret_; }
  
    // Time that access code is valid for.
    base::TimeDelta code_validity() const { return code_validity_; }
  
    // The allowed difference between the clock on child and parent devices.
    base::TimeDelta clock_drift_tolerance() const {
      return clock_drift_tolerance_;
    }
  
    // Converts the AccessCodeConfig object to its dictionary equivalent.
    base::Value ToDictionary() const;
  
   private:
    std::string shared_secret_;
    base::TimeDelta code_validity_;
    base::TimeDelta clock_drift_tolerance_;
  
    DISALLOW_COPY_AND_ASSIGN(AccessCodeConfig);
  };
  
  // Parent access code that can be used to authorize various actions on child
  // user's device.
  // Typical lifetime of the code is 10 minutes and clock difference between
  // generating and validating device is half of the code lifetime. Clock
  // difference is accounted for during code validation.
  class AccessCode {
   public:
    // To create valid AccessCode:
    // * |code| needs to be 6 characters long
    // * |valid_to| needs to be greater than |valid_from|
    AccessCode(const std::string& code,
               base::Time valid_from,
               base::Time valid_to);
    AccessCode(const AccessCode&);
    AccessCode& operator=(const AccessCode&);
    ~AccessCode();
  
    // Parent access code.
    const std::string& code() const { return code_; }
  
    // Code validity start time.
    base::Time valid_from() const { return valid_from_; }
  
    // Code expiration time.
    base::Time valid_to() const { return valid_to_; }
  
    bool operator==(const AccessCode&) const;
    bool operator!=(const AccessCode&) const;
    friend std::ostream& operator<<(std::ostream&, const AccessCode&);
  
   private:
    std::string code_;
    base::Time valid_from_;
    base::Time valid_to_;
  };
  
  // Generates and validates parent access codes.
  // Does not support timestamp from before Unix Epoch.
  class Authenticator {
   public:
    // Granularity of which generation and verification of access code are carried
    // out. Should not exceed code validity period.
    static constexpr base::TimeDelta kAccessCodeGranularity =
        base::TimeDelta::FromMinutes(1);
  
    explicit Authenticator(AccessCodeConfig config);
    ~Authenticator();
  
    // Generates parent access code from the given |timestamp|. Returns the code
    // if generation was successful. |timestamp| needs to be greater or equal Unix
    // Epoch.
    absl::optional<AccessCode> Generate(base::Time timestamp) const;
  
    // Returns AccessCode structure with validity information, if |code| is
    // valid for the given timestamp. |timestamp| needs to be greater or equal
    // Unix Epoch.
    absl::optional<AccessCode> Validate(const std::string& code,
                                        base::Time timestamp) const;
  
   private:
    // Returns AccessCode structure with validity information, if |code| is valid
    // for the range [|valid_from|, |valid_to|). |valid_to| needs to be greater or
    // equal to |valid_from|. |valid_from| needs to be greater or equal Unix
    // Epoch.
    absl::optional<AccessCode> ValidateInRange(const std::string& code,
                                               base::Time valid_from,
                                               base::Time valid_to) const;
  
    // Configuration used to generate and validate parent access code.
    const AccessCodeConfig config_;
  
    // Keyed-hash message authentication generator.
    crypto::HMAC hmac_{crypto::HMAC::SHA1};
  
    DISALLOW_COPY_AND_ASSIGN(Authenticator);
  };
  
  }  // namespace parent_access
  }  // namespace ash
  
  #endif  // CHROME_BROWSER_ASH_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_AUTHENTICATOR_H_
  