1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/local_discovery/privetv3_setup_flow.h"
6
7#include "base/logging.h"
8#include "chrome/browser/local_discovery/gcd_registration_ticket_request.h"
9
10namespace local_discovery {
11
12namespace {
13
14const char kSsidJsonKeyName[] = "wifi.ssid";
15const char kPasswordJsonKeyName[] = "wifi.passphrase";
16const char kTicketJsonKeyName[] = "registration.ticketID";
17const char kUserJsonKeyName[] = "registration.user";
18
19class SetupRequest : public PrivetV3Session::Request {
20 public:
21  explicit SetupRequest(PrivetV3SetupFlow* setup_flow);
22  virtual ~SetupRequest();
23
24  virtual std::string GetName() OVERRIDE { return "/privet/v3/setup/start"; }
25  virtual const base::DictionaryValue& GetInput() OVERRIDE;
26
27  virtual void OnError(PrivetURLFetcher::ErrorType error) OVERRIDE;
28  virtual void OnParsedJson(const base::DictionaryValue& value,
29                            bool has_error) OVERRIDE;
30
31  void SetWiFiCridentials(const std::string& ssid, const std::string& password);
32
33  void SetRegistrationTicket(const std::string& ticket_id,
34                             const std::string& owner_email);
35
36 private:
37  base::DictionaryValue input_;
38  PrivetV3SetupFlow* setup_flow_;
39};
40
41SetupRequest::SetupRequest(PrivetV3SetupFlow* setup_flow)
42    : setup_flow_(setup_flow) {
43}
44
45SetupRequest::~SetupRequest() {
46}
47
48const base::DictionaryValue& SetupRequest::GetInput() {
49  return input_;
50}
51
52void SetupRequest::OnError(PrivetURLFetcher::ErrorType error) {
53  setup_flow_->OnSetupError();
54}
55
56void SetupRequest::OnParsedJson(const base::DictionaryValue& value,
57                                bool has_error) {
58  if (has_error)
59    return setup_flow_->OnSetupError();
60  setup_flow_->OnDeviceRegistered();
61}
62
63void SetupRequest::SetWiFiCridentials(const std::string& ssid,
64                                      const std::string& password) {
65  DCHECK(!ssid.empty());
66  DCHECK(!password.empty());
67  input_.SetString(kSsidJsonKeyName, ssid);
68  input_.SetString(kPasswordJsonKeyName, password);
69}
70
71void SetupRequest::SetRegistrationTicket(const std::string& ticket_id,
72                                         const std::string& owner_email) {
73  DCHECK(!ticket_id.empty());
74  DCHECK(!owner_email.empty());
75  input_.SetString(kTicketJsonKeyName, ticket_id);
76  input_.SetString(kUserJsonKeyName, owner_email);
77}
78
79}  // namespace
80
81PrivetV3SetupFlow::Delegate::~Delegate() {
82}
83
84PrivetV3SetupFlow::PrivetV3SetupFlow(Delegate* delegate)
85    : delegate_(delegate), weak_ptr_factory_(this) {
86}
87
88PrivetV3SetupFlow::~PrivetV3SetupFlow() {
89}
90
91void PrivetV3SetupFlow::Register(const std::string& service_name) {
92  service_name_ = service_name;
93  ticket_request_ = delegate_->CreateApiFlow();
94  if (!ticket_request_) {
95    OnSetupError();
96    return;
97  }
98  scoped_ptr<GCDApiFlow::Request> ticket_request(
99      new GCDRegistrationTicketRequest(
100          base::Bind(&PrivetV3SetupFlow::OnTicketCreated,
101                     weak_ptr_factory_.GetWeakPtr())));
102  ticket_request_->Start(ticket_request.Pass());
103}
104
105#if defined(ENABLE_WIFI_BOOTSTRAPPING)
106void PrivetV3SetupFlow::SetupWifiAndRegister(const std::string& device_ssid) {
107  NOTIMPLEMENTED();
108}
109#endif  // ENABLE_WIFI_BOOTSTRAPPING
110
111void PrivetV3SetupFlow::OnSetupConfirmationNeeded(
112    const std::string& confirmation_code,
113    extensions::api::gcd_private::ConfirmationType confirmation_type) {
114  delegate_->ConfirmSecurityCode(confirmation_code,
115                                 base::Bind(&PrivetV3SetupFlow::OnCodeConfirmed,
116                                            weak_ptr_factory_.GetWeakPtr(),
117                                            confirmation_code));
118}
119
120void PrivetV3SetupFlow::OnSessionStatus(
121    extensions::api::gcd_private::Status status) {
122  if (status == extensions::api::gcd_private::STATUS_SUCCESS) {
123    DCHECK(setup_request_);
124    session_->StartRequest(setup_request_.get());
125  } else {
126    OnSetupError();
127  }
128}
129
130void PrivetV3SetupFlow::OnSetupError() {
131  delegate_->OnSetupError();
132}
133
134void PrivetV3SetupFlow::OnDeviceRegistered() {
135  delegate_->OnSetupDone();
136}
137
138void PrivetV3SetupFlow::OnTicketCreated(const std::string& ticket_id,
139                                        const std::string& device_id) {
140  if (ticket_id.empty() || device_id.empty()) {
141    OnSetupError();
142    return;
143  }
144  // TODO(vitalybuka): Implement success check by polling status of device_id_.
145  device_id_ = device_id;
146  SetupRequest* setup_request = new SetupRequest(this);
147  setup_request_.reset(setup_request);
148  setup_request->SetRegistrationTicket(ticket_id, "me");
149  delegate_->CreatePrivetV3Client(
150      service_name_,
151      base::Bind(&PrivetV3SetupFlow::OnPrivetClientCreated,
152                 weak_ptr_factory_.GetWeakPtr()));
153}
154
155void PrivetV3SetupFlow::OnPrivetClientCreated(
156    scoped_ptr<PrivetHTTPClient> privet_http_client) {
157  if (!privet_http_client) {
158    OnSetupError();
159    return;
160  }
161  session_.reset(new PrivetV3Session(privet_http_client.Pass(), this));
162  session_->Start();
163}
164
165void PrivetV3SetupFlow::OnCodeConfirmed(const std::string& code, bool success) {
166  if (!success)
167    return OnSetupError();
168  session_->ConfirmCode(code);
169}
170
171}  // namespace local_discovery
172