Diff
Not logged in

Differences From Artifact [516193f22e]:

To Artifact [0f418b907b]:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
..
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

94

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
...
210
211
212
213
214
215
216
217
218

219
220
221
222
223
224
225
...
258
259
260
261
262
263
264
265
266

267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293

294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360

361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
...
390
391
392
393
394
395
396
397
398
399
400
401
402

403
404
405
406
407
408
409
410
...
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
...
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
...
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
...
554
555
556
557
558
559
560
561

562
563

564
565
566
567
568
569
570
571
572
573
574
...
581
582
583
584
585
586
587
588

589
590
591
592
593
594
595
596
...
608
609
610
611
612
613
614
615

616
617
618
619
620
621
622
623
...
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
...
643
644
645
646
647
648
649
650
651


652
653
654
655
656
657
658
...
676
677
678
679
680
681
682
683
684


685
686
687
688
689
690
691
// Copyright 2015 MaidSafe.net limited.
//
// This SAFE Network Software is licensed to you under (1) the MaidSafe.net Commercial License,
// version 1.0 or later, or (2) The General Public License (GPL), version 3, depending on which
// licence you accepted on initial access to the Software (the "Licences").
//
// By contributing code to the SAFE Network Software, or to this project generally, you agree to be
// bound by the terms of the MaidSafe Contributor Agreement, version 1.0.  This, along with the
// Licenses can be found in the root directory of this project at LICENSE, COPYING and CONTRIBUTOR.
//
// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.
//
// Please review the Licences for the specific language governing permissions and limitations
// relating to use of the SAFE Network Software.


use core::client::Client;
use core::errors::CoreError;
use core::structured_data_operations::unversioned;
use dns::errors::DnsError;
use maidsafe_utilities::serialisation::{deserialise, serialise};
use nfs::metadata::directory_key::DirectoryKey;
................................................................................
    client: Arc<Mutex<Client>>,
}

impl DnsOperations {
    /// Create a new instance of DnsOperations. It is intended that only one of this be created as
    /// it operates on global data such as files.
    pub fn new(client: Arc<Mutex<Client>>) -> Result<DnsOperations, DnsError> {
        try!(dns_configuration::initialise_dns_configuaration(client.clone()));

        Ok(DnsOperations { client: client })
    }

    /// Create a new instance of DnsOperations. This is used for an unregistered client and will
    /// have very limited set of functionalities - mostly reads. This is ideal for browsers etc.,
    /// which only want to fetch from the Network, not mutate it.
................................................................................
    /// It is intended that only one of this be created as it operates on global data such as
    /// files.
    pub fn new_unregistered(unregistered_client: Arc<Mutex<Client>>) -> DnsOperations {
        DnsOperations { client: unregistered_client }
    }

    /// Register one's own Dns - eg., pepsico.com, spandansharma.com, krishnakumar.in etc
    #[cfg_attr(feature="clippy", allow(too_many_arguments))]
    pub fn register_dns(&self,
                        long_name: String,
                        public_messaging_encryption_key: &box_::PublicKey,
                        secret_messaging_encryption_key: &box_::SecretKey,
                        services: &[(String, DirectoryKey)],
                        owners: BTreeSet<sign::PublicKey>,
                        private_signing_key: &sign::SecretKey,
                        data_encryption_keys: Option<(&box_::PublicKey,
                                                      &box_::SecretKey,
                                                      &box_::Nonce)>)
                        -> Result<(), DnsError> {
        trace!("Registering dns with name: {}", long_name);

        let mut saved_configs = try!(dns_configuration::get_dns_configuration_data(self.client
            .clone()));

        if saved_configs.iter().any(|config| config.long_name == long_name) {
            Err(DnsError::DnsNameAlreadyRegistered)
        } else {
            let identifier = XorName(sha256::hash(long_name.as_bytes()).0);

            let dns_record = Dns {
                long_name: long_name.clone(),
                services: services.iter().cloned().collect(),
                encryption_key: *public_messaging_encryption_key,
            };

            let mut struct_data = try!(unversioned::create(self.client.clone(),
                                                           TYPE_TAG_DNS_PACKET,
                                                           identifier,
                                                           0,
                                                           try!(serialise(&dns_record)),
                                                           owners.clone(),
                                                           data_encryption_keys));

            let _ = try!(struct_data.add_signature(&(try!(owners.iter()

                                         .nth(0)
                                         .ok_or_else(|| CoreError::ReceivedUnexpectedData))
                                     .clone(),
                                 private_signing_key.clone()))
                .map_err(CoreError::from));

            match Client::put_recover(self.client.clone(), Data::Structured(struct_data), None) {
                Ok(()) => (),
                Err(CoreError::MutationFailure { reason: MutationError::DataExists, .. }) => {
                    return Err(DnsError::DnsNameAlreadyRegistered)
                }
                Err(err) => return Err(From::from(err)),
            }

            trace!("Adding encryption key pair to the retrieved saved dns configuration.");
            saved_configs.push(dns_configuration::DnsConfiguration {
                long_name: long_name,
                encryption_keypair: (*public_messaging_encryption_key,
                                     secret_messaging_encryption_key.clone()),
            });
            try!(dns_configuration::write_dns_configuration_data(self.client.clone(),
                                                                 &saved_configs));

            Ok(())
        }
    }

    /// Delete the Dns-Record
    pub fn delete_dns(&self,
                      long_name: &str,
                      private_signing_key: &sign::SecretKey)
                      -> Result<(), DnsError> {
        trace!("Deleting dns with name: {}", long_name);

        let mut saved_configs = try!(dns_configuration::get_dns_configuration_data(self.client
            .clone()));
        let pos = try!(saved_configs.iter()
            .position(|config| config.long_name == *long_name)
            .ok_or(DnsError::DnsRecordNotFound));

        match self.get_housing_structured_data(long_name) {
            Ok(prev_struct_data) => {
                let mut struct_data = try!(unversioned::create(self.client.clone(),
                                                               TYPE_TAG_DNS_PACKET,
                                                               *prev_struct_data.name(),
                                                               prev_struct_data.get_version() + 1,
                                                               vec![],
                                                               prev_struct_data.get_owners()
                                                                   .clone(),
                                                               None));
                let owner_key = try!(unwrap!(self.client.lock()).get_public_signing_key()).clone();

                let _ = try!(struct_data.add_signature(&(owner_key, private_signing_key.clone()))
                    .map_err(CoreError::from));
                try!(Client::delete_recover(self.client.clone(),
                                            Data::Structured(struct_data),
                                            None));
            }
            Err(DnsError::CoreError(CoreError::GetFailure {
                reason: GetError::NoSuchData,
                ..
            })) => (),
            Err(e) => return Err(e),
        };

        trace!("Removing dns entry from the retrieved saved config.");
        let _ = saved_configs.remove(pos);
        try!(dns_configuration::write_dns_configuration_data(self.client.clone(), &saved_configs));

        Ok(())
    }

    /// Get all the Dns-names registered by the user so far in the network.
    pub fn get_all_registered_names(&self) -> Result<Vec<String>, DnsError> {
        trace!("Get all dns long names that we own.");
................................................................................
    pub fn get_messaging_encryption_keys
        (&self,
         long_name: &str)
         -> Result<(box_::PublicKey, box_::SecretKey), DnsError> {
        trace!("Get messaging encryption keys for owned dns with name: {}",
               long_name);

        let dns_config_record = try!(self.find_dns_record(long_name));
        Ok(dns_config_record.encryption_keypair.clone())
    }

    /// Get all the services (www, blog, micro-blog etc) that user has associated with this
    /// Dns-name
    pub fn get_all_services(&self,
                            long_name: &str,
................................................................................
                            data_decryption_keys: Option<(&box_::PublicKey,
                                                          &box_::SecretKey,
                                                          &box_::Nonce)>)
                            -> Result<Vec<String>, DnsError> {
        trace!("Get all services for the dns with name: {}", long_name);

        let (_, dns_record) =
            try!(self.get_housing_structured_data_and_dns_record(long_name, data_decryption_keys));
        Ok(dns_record.services.keys().cloned().collect())
    }

    /// Get the home directory (eg., homepage containing HOME.html, INDEX.html) for the given
    /// service.
    pub fn get_service_home_directory_key(&self,
                                          long_name: &str,
................................................................................
                                          -> Result<DirectoryKey, DnsError> {
        trace!("Get service home directory key (to locate the home directory on SAFE Network) \
                for \"//{}.{}\".",
               service_name,
               long_name);

        let (_, dns_record) =
            try!(self.get_housing_structured_data_and_dns_record(long_name, data_decryption_keys));
        dns_record.services

            .get(service_name)
            .cloned()
            .ok_or(DnsError::ServiceNotFound)
    }

    /// Add a new service for the given Dns-name.
    pub fn add_service(&self,
................................................................................
                                     private_signing_key,
                                     data_encryption_decryption_keys)
    }

    fn find_dns_record(&self,
                       long_name: &str)
                       -> Result<dns_configuration::DnsConfiguration, DnsError> {
        let config_vec = try!(dns_configuration::get_dns_configuration_data(self.client.clone()));
        config_vec.iter()

            .find(|config| config.long_name == *long_name)
            .cloned()
            .ok_or(DnsError::DnsRecordNotFound)
    }

    fn add_remove_service_impl(&self,
                               long_name: &str,
                               service: (String, Option<DirectoryKey>),
                               private_signing_key: &sign::SecretKey,
                               data_encryption_decryption_keys: Option<(&box_::PublicKey,
                                                                        &box_::SecretKey,
                                                                        &box_::Nonce)>)
                               -> Result<(), DnsError> {
        let _ = try!(self.find_dns_record(long_name));

        let is_add_service = service.1.is_some();
        let (prev_struct_data, mut dns_record) =
            try!(self.get_housing_structured_data_and_dns_record(long_name,
                                                                 data_encryption_decryption_keys));

        if !is_add_service && !dns_record.services.contains_key(&service.0) {
            Err(DnsError::ServiceNotFound)
        } else if is_add_service && dns_record.services.contains_key(&service.0) {
            Err(DnsError::ServiceAlreadyExists)
        } else {
            if is_add_service {
                debug!("Inserting service ...");

                let _ = dns_record.services
                    .insert(service.0,
                            try!(service.1
                                .ok_or(DnsError::from("Programming Error - Investigate !!"))));
            } else {
                debug!("Removing service ...");
                let _ = dns_record.services.remove(&service.0);
            }

            let mut struct_data = try!(unversioned::create(self.client.clone(),
                                                           TYPE_TAG_DNS_PACKET,
                                                           *prev_struct_data.name(),
                                                           prev_struct_data.get_version() + 1,
                                                           try!(serialise(&dns_record)),
                                                           prev_struct_data.get_owners().clone(),
                                                           data_encryption_decryption_keys));
            let owner_key = unwrap!(prev_struct_data.get_owners().iter().nth(0),
                                    "Logic error: SD doesn't have any owners")
                .clone();
            let _ = try!(struct_data.add_signature(&(owner_key, private_signing_key.clone()))
                .map_err(CoreError::from));

            let resp_getter = try!(unwrap!(self.client.lock())
                .post(Data::Structured(struct_data), None));
            try!(resp_getter.get());

            Ok(())
        }
    }

    fn get_housing_structured_data_and_dns_record(&self,
                                                  long_name: &str,
                                                  data_decryption_keys: Option<(&box_::PublicKey,
                                                                                &box_::SecretKey,
                                                                                &box_::Nonce)>)
                                                  -> Result<(StructuredData, Dns), DnsError> {
        let struct_data = try!(self.get_housing_structured_data(long_name));
        let dns_record = try!(deserialise(&try!(unversioned::get_data(self.client.clone(),
                                                                      &struct_data,
                                                                      data_decryption_keys))));
        Ok((struct_data, dns_record))
    }

    fn get_housing_structured_data(&self, long_name: &str) -> Result<StructuredData, DnsError> {
        trace!("Fetch capsule from network for dns with name: {}",
               long_name);

        let identifier = XorName(sha256::hash(long_name.as_bytes()).0);
        let request = DataIdentifier::Structured(identifier, TYPE_TAG_DNS_PACKET);
        let response_getter = try!(unwrap!(self.client.lock()).get(request, None));
        if let Data::Structured(struct_data) = try!(response_getter.get()) {
            Ok(struct_data)
        } else {
            Err(DnsError::from(CoreError::ReceivedUnexpectedData))
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable)]
struct Dns {
    long_name: String,
    services: ::std::collections::HashMap<String, DirectoryKey>,
    encryption_key: box_::PublicKey,
}

#[cfg(test)]
mod test {

    use core::client::Client;
    use core::utility::{generate_random_string, test_utils};
    use dns::errors::DnsError;
    use nfs::AccessLevel;
    use nfs::metadata::directory_key::DirectoryKey;
    use routing::{XOR_NAME_LEN, XorName};
    use rust_sodium::crypto::box_;
    use std::collections::BTreeSet;
    use std::sync::{Arc, Mutex};
    use super::*;

    #[test]
    fn register_and_delete_dns() {
        let client = Arc::new(Mutex::new(unwrap!(test_utils::get_client())));
        let dns_operations = unwrap!(DnsOperations::new(client.clone()));

        let dns_name = unwrap!(generate_random_string(10));
        let messaging_keypair = box_::gen_keypair();
        let mut owners = BTreeSet::new();
        owners.insert(unwrap!(unwrap!(client.lock()).get_public_signing_key()).clone());

        let secret_signing_key = unwrap!(unwrap!(client.lock()).get_secret_signing_key()).clone();

        // Trying to delete before we've registered should give the right error.
        match dns_operations.delete_dns(&dns_name, &secret_signing_key) {
            Ok(x) => {
                panic!("Deleting before we registered should have been an error.
................................................................................
                       x)
            }
            Err(DnsError::DnsRecordNotFound) => (),
            Err(e) => panic!("Got the wrong error: {:?}", e),
        };

        // Trying to delete when it's in our config but not on the network should succeed.
        let mut saved_configs =
            unwrap!(dns_configuration::get_dns_configuration_data(dns_operations.client
                .clone()));
        saved_configs.push(dns_configuration::DnsConfiguration {
            long_name: dns_name.clone(),
            encryption_keypair: (messaging_keypair.0, messaging_keypair.1.clone()),

        });
        unwrap!(dns_configuration::write_dns_configuration_data(dns_operations.client.clone(),
                                                                &saved_configs));
        unwrap!(dns_operations.delete_dns(&dns_name, &secret_signing_key));

        // Trying to delete a second time should error again.
        match dns_operations.delete_dns(&dns_name, &secret_signing_key) {
            Ok(x) => {
................................................................................

        // Re-registering by the same client is not allowed again (check that we're back in a sane
        // state).
        match dns_operations.register_dns(dns_name.clone(),
                                          &messaging_keypair.0,
                                          &messaging_keypair.1,
                                          &[],
                                          owners.clone(),
                                          &secret_signing_key,
                                          None) {
            Ok(_) => panic!("Should have been an error"),
            Err(DnsError::DnsNameAlreadyRegistered) => (),
            Err(error) => panic!("{:?}", error),
        }

................................................................................
        // Re-registering by a different new_client is not allowed
        {
            let new_client = Arc::new(Mutex::new(unwrap!(test_utils::get_client())));
            let dns_operations = unwrap!(DnsOperations::new(new_client.clone()));

            let messaging_keypair = box_::gen_keypair();
            let mut owners = BTreeSet::new();
            owners.insert(unwrap!(unwrap!(new_client.lock()).get_public_signing_key()).clone());

            let secret_signing_key = unwrap!(unwrap!(new_client.lock()).get_secret_signing_key())
                .clone();
            match dns_operations.register_dns(dns_name.clone(),
                                              &messaging_keypair.0,
                                              &messaging_keypair.1,
                                              &[],
                                              owners.clone(),
                                              &secret_signing_key,
                                              None) {
                Ok(_) => panic!("Should have been an error"),
                Err(DnsError::DnsNameAlreadyRegistered) => (),
                Err(error) => panic!("{:?}", error),
            }
        }
................................................................................
                                ("bad-ass".to_string(),
                                 DirectoryKey::new(XorName([123; XOR_NAME_LEN]),
                                                   15000,
                                                   false,
                                                   AccessLevel::Public))];

        let mut owners = BTreeSet::new();
        owners.insert(unwrap!(unwrap!(client.lock()).get_public_signing_key()).clone());

        let secret_signing_key = unwrap!(unwrap!(client.lock()).get_secret_signing_key()).clone();

        // Register
        unwrap!(dns_operations.register_dns(dns_name.clone(),
                                            &messaging_keypair.0,
                                            &messaging_keypair.1,
                                            &services,
                                            owners.clone(),
                                            &secret_signing_key,
                                            None));

        // Get all dns-names
        let dns_records_vec = unwrap!(dns_operations.get_all_registered_names());
        assert_eq!(dns_records_vec.len(), 1);

................................................................................
        let unregistered_client =
            Arc::new(Mutex::new(unwrap!(Client::create_unregistered_client())));
        let dns_operations_unregistered = DnsOperations::new_unregistered(unregistered_client);

        // Get all services for a dns-name
        let services_vec = unwrap!(dns_operations_unregistered.get_all_services(&dns_name, None));
        assert_eq!(services.len(), services_vec.len());
        assert!(services.iter()

            .all(|&(ref a, _)| services_vec.iter().find(|b| *a == **b).is_some()));


        assert!(dns_operations.get_service_home_directory_key(&"bogus".to_string(),
                                                              &services[0].0,
                                                              None)
                              .is_err());

        // Get information about a service - the home-directory and its type
        let home_dir_key_result =
            dns_operations_unregistered.get_service_home_directory_key(&dns_name,
                                                                       &services[1].0,
                                                                       None);
        let home_dir_key = unwrap!(home_dir_key_result);
................................................................................
                                              &secret_signing_key,
                                              None));
        ::std::thread::sleep(::std::time::Duration::from_secs(1));

        // Get all services
        let services_vec = unwrap!(dns_operations_unregistered.get_all_services(&dns_name, None));
        assert_eq!(services.len(), services_vec.len());
        assert!(services.iter()

            .all(|&(ref a, _)| services_vec.iter().find(|b| *a == **b).is_some()));

        // Try to enquire about a deleted service
        match dns_operations_unregistered.get_service_home_directory_key(&dns_name,
                                                                         &removed_service.0,
                                                                         None) {
            Ok(_) => panic!("Should have been an error"),
            Err(DnsError::ServiceNotFound) => (),
................................................................................
                                           services[services_size - 1].clone(),
                                           &secret_signing_key,
                                           None));

        // Get all services
        let services_vec = unwrap!(dns_operations_unregistered.get_all_services(&dns_name, None));
        assert_eq!(services.len(), services_vec.len());
        assert!(services.iter()

            .all(|&(ref a, _)| services_vec.iter().find(|b| *a == **b).is_some()));
    }

    #[test]
    #[cfg(feature = "use-mock-routing")]
    fn register_and_delete_dns_internal_error_recovery() {
        use core::errors::CoreError;
        use nfs::errors::NfsError;
................................................................................
        unwrap!(maidsafe_utilities::log::init(true));

        let client = Arc::new(Mutex::new(unwrap!(test_utils::get_client())));
        let dns_operations = unwrap!(DnsOperations::new(client.clone()));
        let dns_name = unwrap!(generate_random_string(10));
        let messaging_keypair = box_::gen_keypair();
        let mut owners = BTreeSet::new();
        owners.insert(unwrap!(unwrap!(client.lock()).get_public_signing_key()).clone());
        let secret_signing_key = unwrap!(unwrap!(client.lock()).get_secret_signing_key()).clone();

        // Limit of `Some(2)` would prevent the mutation to happen. We want one
        // `Mutation` exactly at this point
        unwrap!(client.lock()).set_network_limits(Some(3));

        info!("Fail to register the name");
................................................................................
                                          &messaging_keypair.0,
                                          &messaging_keypair.1,
                                          &[],
                                          owners.clone(),
                                          &secret_signing_key,
                                          None) {
            Err(DnsError::NfsError(NfsError::CoreError(CoreError::GetFailure {
                reason: GetError::NetworkOther(ref s), ..
            }))) if s == "Max operations exhausted" => (),


            Ok(()) => panic!("Operation unexpectedly had succeed"),
            Err(e) => panic!("Unexpected error {:?}", e),
        }

        // Remove artificial network failure
        unwrap!(client.lock()).set_network_limits(None);

................................................................................
                                            &secret_signing_key,
                                            None));

        info!("Delete with simulated failure");
        unwrap!(client.lock()).set_network_limits(Some(5));
        match dns_operations.delete_dns(&dns_name, &secret_signing_key) {
            Err(DnsError::NfsError(NfsError::CoreError(CoreError::GetFailure {
                reason: GetError::NetworkOther(ref s), ..
            }))) if s == "Max operations exhausted" => (),


            Ok(()) => panic!("Operation unexpectedly had succeed"),
            Err(e) => panic!("Unexpected error {:?}", e),
        }

        // Remove artificial network failure
        unwrap!(client.lock()).set_network_limits(None);








|
|







<







 







|







 







|













|
|
>
|










|
|
|
|
|
|
|
>
|
>
|
|
<

|











|
|
|
|
|
<












|
|
|

|



|
|
|
|
|
|
<
|
|
>
|
|
|
<
<


|
<
|





|







 







|







 







|







 







|
|
>







 







|
|
>













|



|
|








>
|
|
|
|





|
|
|
|
|
|
|
|
|
|
|
|

|
|
|










|
|
|
|
|









|
|







|








>









<









|







 







|
|
|

|
|
>
|







 







|







 







|







|







 







|








|







 







|
>
|
<
>
|
|
|
|







 







|
>
|







 







|
>
|







 







|







 







|
|
>
>







 







|
|
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

17
18
19
20
21
22
23
..
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
..
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

143
144
145
146
147
148


149
150
151

152
153
154
155
156
157
158
159
160
161
162
163
164
165
...
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370

371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
...
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
...
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
...
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
...
555
556
557
558
559
560
561
562
563
564

565
566
567
568
569
570
571
572
573
574
575
576
...
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
...
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
...
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
...
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
...
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
// Copyright 2015 MaidSafe.net limited.
//
// This SAFE Network Software is licensed to you under (1) the MaidSafe.net Commercial License,
// version 1.0 or later, or (2) The General Public License (GPL), version 3, depending on which
// licence you accepted on initial access to the Software (the "Licences").
//
// By contributing code to the SAFE Network Software, or to this project generally, you agree to be
// bound by the terms of the MaidSafe Contributor Agreement.  This, along with the Licenses can be
// found in the root directory of this project at LICENSE, COPYING and CONTRIBUTOR.
//
// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.
//
// Please review the Licences for the specific language governing permissions and limitations
// relating to use of the SAFE Network Software.


use core::client::Client;
use core::errors::CoreError;
use core::structured_data_operations::unversioned;
use dns::errors::DnsError;
use maidsafe_utilities::serialisation::{deserialise, serialise};
use nfs::metadata::directory_key::DirectoryKey;
................................................................................
    client: Arc<Mutex<Client>>,
}

impl DnsOperations {
    /// Create a new instance of DnsOperations. It is intended that only one of this be created as
    /// it operates on global data such as files.
    pub fn new(client: Arc<Mutex<Client>>) -> Result<DnsOperations, DnsError> {
        dns_configuration::initialise_dns_configuaration(client.clone())?;

        Ok(DnsOperations { client: client })
    }

    /// Create a new instance of DnsOperations. This is used for an unregistered client and will
    /// have very limited set of functionalities - mostly reads. This is ideal for browsers etc.,
    /// which only want to fetch from the Network, not mutate it.
................................................................................
    /// It is intended that only one of this be created as it operates on global data such as
    /// files.
    pub fn new_unregistered(unregistered_client: Arc<Mutex<Client>>) -> DnsOperations {
        DnsOperations { client: unregistered_client }
    }

    /// Register one's own Dns - eg., pepsico.com, spandansharma.com, krishnakumar.in etc
    #[cfg_attr(feature="cargo-clippy", allow(too_many_arguments))]
    pub fn register_dns(&self,
                        long_name: String,
                        public_messaging_encryption_key: &box_::PublicKey,
                        secret_messaging_encryption_key: &box_::SecretKey,
                        services: &[(String, DirectoryKey)],
                        owners: BTreeSet<sign::PublicKey>,
                        private_signing_key: &sign::SecretKey,
                        data_encryption_keys: Option<(&box_::PublicKey,
                                                      &box_::SecretKey,
                                                      &box_::Nonce)>)
                        -> Result<(), DnsError> {
        trace!("Registering dns with name: {}", long_name);

        let mut saved_configs = dns_configuration::get_dns_configuration_data(self.client.clone())?;
        if saved_configs
               .iter()
               .any(|config| config.long_name == long_name) {
            Err(DnsError::DnsNameAlreadyRegistered)
        } else {
            let identifier = XorName(sha256::hash(long_name.as_bytes()).0);

            let dns_record = Dns {
                long_name: long_name.clone(),
                services: services.iter().cloned().collect(),
                encryption_key: *public_messaging_encryption_key,
            };

            let mut struct_data = unversioned::create(self.client.clone(),
                                                      TYPE_TAG_DNS_PACKET,
                                                      identifier,
                                                      0,
                                                      serialise(&dns_record)?,
                                                      owners.clone(),
                                                      data_encryption_keys)?;
            let _ = struct_data
                .add_signature(&(*owners
                                      .iter()
                                      .nth(0)
                                      .ok_or_else(|| CoreError::ReceivedUnexpectedData)?,

                                 private_signing_key.clone()))
                .map_err(CoreError::from)?;

            match Client::put_recover(self.client.clone(), Data::Structured(struct_data), None) {
                Ok(()) => (),
                Err(CoreError::MutationFailure { reason: MutationError::DataExists, .. }) => {
                    return Err(DnsError::DnsNameAlreadyRegistered)
                }
                Err(err) => return Err(From::from(err)),
            }

            trace!("Adding encryption key pair to the retrieved saved dns configuration.");
            saved_configs.push(dns_configuration::DnsConfiguration {
                                   long_name: long_name,
                                   encryption_keypair: (*public_messaging_encryption_key,
                                                        secret_messaging_encryption_key.clone()),
                               });
            dns_configuration::write_dns_configuration_data(self.client.clone(), &saved_configs)?;


            Ok(())
        }
    }

    /// Delete the Dns-Record
    pub fn delete_dns(&self,
                      long_name: &str,
                      private_signing_key: &sign::SecretKey)
                      -> Result<(), DnsError> {
        trace!("Deleting dns with name: {}", long_name);

        let mut saved_configs = dns_configuration::get_dns_configuration_data(self.client.clone())?;
        let pos = saved_configs
            .iter()
            .position(|config| config.long_name == *long_name)
            .ok_or(DnsError::DnsRecordNotFound)?;

        match self.get_housing_structured_data(long_name) {
            Ok(prev_struct_data) => {
                let mut struct_data = unversioned::create(self.client.clone(),
                                                          TYPE_TAG_DNS_PACKET,
                                                          *prev_struct_data.name(),
                                                          prev_struct_data.get_version() + 1,
                                                          vec![],
                                                          prev_struct_data.get_owners().clone(),

                                                          None)?;
                let owner_key = *unwrap!(self.client.lock()).get_public_signing_key()?;
                let _ = struct_data
                    .add_signature(&(owner_key, private_signing_key.clone()))
                    .map_err(CoreError::from)?;
                Client::delete_recover(self.client.clone(), Data::Structured(struct_data), None)?;


            }
            Err(DnsError::CoreError(CoreError::GetFailure {
                                        reason: GetError::NoSuchData, ..

                                    })) => (),
            Err(e) => return Err(e),
        };

        trace!("Removing dns entry from the retrieved saved config.");
        let _ = saved_configs.remove(pos);
        dns_configuration::write_dns_configuration_data(self.client.clone(), &saved_configs)?;

        Ok(())
    }

    /// Get all the Dns-names registered by the user so far in the network.
    pub fn get_all_registered_names(&self) -> Result<Vec<String>, DnsError> {
        trace!("Get all dns long names that we own.");
................................................................................
    pub fn get_messaging_encryption_keys
        (&self,
         long_name: &str)
         -> Result<(box_::PublicKey, box_::SecretKey), DnsError> {
        trace!("Get messaging encryption keys for owned dns with name: {}",
               long_name);

        let dns_config_record = self.find_dns_record(long_name)?;
        Ok(dns_config_record.encryption_keypair.clone())
    }

    /// Get all the services (www, blog, micro-blog etc) that user has associated with this
    /// Dns-name
    pub fn get_all_services(&self,
                            long_name: &str,
................................................................................
                            data_decryption_keys: Option<(&box_::PublicKey,
                                                          &box_::SecretKey,
                                                          &box_::Nonce)>)
                            -> Result<Vec<String>, DnsError> {
        trace!("Get all services for the dns with name: {}", long_name);

        let (_, dns_record) =
            self.get_housing_structured_data_and_dns_record(long_name, data_decryption_keys)?;
        Ok(dns_record.services.keys().cloned().collect())
    }

    /// Get the home directory (eg., homepage containing HOME.html, INDEX.html) for the given
    /// service.
    pub fn get_service_home_directory_key(&self,
                                          long_name: &str,
................................................................................
                                          -> Result<DirectoryKey, DnsError> {
        trace!("Get service home directory key (to locate the home directory on SAFE Network) \
                for \"//{}.{}\".",
               service_name,
               long_name);

        let (_, dns_record) =
            self.get_housing_structured_data_and_dns_record(long_name, data_decryption_keys)?;
        dns_record
            .services
            .get(service_name)
            .cloned()
            .ok_or(DnsError::ServiceNotFound)
    }

    /// Add a new service for the given Dns-name.
    pub fn add_service(&self,
................................................................................
                                     private_signing_key,
                                     data_encryption_decryption_keys)
    }

    fn find_dns_record(&self,
                       long_name: &str)
                       -> Result<dns_configuration::DnsConfiguration, DnsError> {
        let config_vec = dns_configuration::get_dns_configuration_data(self.client.clone())?;
        config_vec
            .iter()
            .find(|config| config.long_name == *long_name)
            .cloned()
            .ok_or(DnsError::DnsRecordNotFound)
    }

    fn add_remove_service_impl(&self,
                               long_name: &str,
                               service: (String, Option<DirectoryKey>),
                               private_signing_key: &sign::SecretKey,
                               data_encryption_decryption_keys: Option<(&box_::PublicKey,
                                                                        &box_::SecretKey,
                                                                        &box_::Nonce)>)
                               -> Result<(), DnsError> {
        let _ = self.find_dns_record(long_name)?;

        let is_add_service = service.1.is_some();
        let (prev_struct_data, mut dns_record) =
            self.get_housing_structured_data_and_dns_record(long_name,
                                                            data_encryption_decryption_keys)?;

        if !is_add_service && !dns_record.services.contains_key(&service.0) {
            Err(DnsError::ServiceNotFound)
        } else if is_add_service && dns_record.services.contains_key(&service.0) {
            Err(DnsError::ServiceAlreadyExists)
        } else {
            if is_add_service {
                debug!("Inserting service ...");
                let _ =
                    dns_record.services
                        .insert(service.0,
                                service.1.ok_or_else(
                                    || DnsError::from("Programming Error - Investigate !!"))?);
            } else {
                debug!("Removing service ...");
                let _ = dns_record.services.remove(&service.0);
            }

            let mut struct_data = unversioned::create(self.client.clone(),
                                                      TYPE_TAG_DNS_PACKET,
                                                      *prev_struct_data.name(),
                                                      prev_struct_data.get_version() + 1,
                                                      serialise(&dns_record)?,
                                                      prev_struct_data.get_owners().clone(),
                                                      data_encryption_decryption_keys)?;
            let owner_key = *unwrap!(prev_struct_data.get_owners().iter().nth(0),
                                     "Logic error: SD doesn't have any owners");
            let _ = struct_data
                .add_signature(&(owner_key, private_signing_key.clone()))
                .map_err(CoreError::from)?;

            let resp_getter = unwrap!(self.client.lock())
                .post(Data::Structured(struct_data), None)?;
            resp_getter.get()?;

            Ok(())
        }
    }

    fn get_housing_structured_data_and_dns_record(&self,
                                                  long_name: &str,
                                                  data_decryption_keys: Option<(&box_::PublicKey,
                                                                                &box_::SecretKey,
                                                                                &box_::Nonce)>)
-> Result<(StructuredData, Dns), DnsError>{
        let struct_data = self.get_housing_structured_data(long_name)?;
        let dns_record = deserialise(&unversioned::get_data(self.client.clone(),
                                                            &struct_data,
                                                            data_decryption_keys)?)?;
        Ok((struct_data, dns_record))
    }

    fn get_housing_structured_data(&self, long_name: &str) -> Result<StructuredData, DnsError> {
        trace!("Fetch capsule from network for dns with name: {}",
               long_name);

        let identifier = XorName(sha256::hash(long_name.as_bytes()).0);
        let request = DataIdentifier::Structured(identifier, TYPE_TAG_DNS_PACKET);
        let response_getter = unwrap!(self.client.lock()).get(request, None)?;
        if let Data::Structured(struct_data) = response_getter.get()? {
            Ok(struct_data)
        } else {
            Err(DnsError::from(CoreError::ReceivedUnexpectedData))
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
struct Dns {
    long_name: String,
    services: ::std::collections::HashMap<String, DirectoryKey>,
    encryption_key: box_::PublicKey,
}

#[cfg(test)]
mod test {
    use super::*;
    use core::client::Client;
    use core::utility::{generate_random_string, test_utils};
    use dns::errors::DnsError;
    use nfs::AccessLevel;
    use nfs::metadata::directory_key::DirectoryKey;
    use routing::{XOR_NAME_LEN, XorName};
    use rust_sodium::crypto::box_;
    use std::collections::BTreeSet;
    use std::sync::{Arc, Mutex};


    #[test]
    fn register_and_delete_dns() {
        let client = Arc::new(Mutex::new(unwrap!(test_utils::get_client())));
        let dns_operations = unwrap!(DnsOperations::new(client.clone()));

        let dns_name = unwrap!(generate_random_string(10));
        let messaging_keypair = box_::gen_keypair();
        let mut owners = BTreeSet::new();
        owners.insert(*unwrap!(unwrap!(client.lock()).get_public_signing_key()));

        let secret_signing_key = unwrap!(unwrap!(client.lock()).get_secret_signing_key()).clone();

        // Trying to delete before we've registered should give the right error.
        match dns_operations.delete_dns(&dns_name, &secret_signing_key) {
            Ok(x) => {
                panic!("Deleting before we registered should have been an error.
................................................................................
                       x)
            }
            Err(DnsError::DnsRecordNotFound) => (),
            Err(e) => panic!("Got the wrong error: {:?}", e),
        };

        // Trying to delete when it's in our config but not on the network should succeed.
        let config_data =
            dns_configuration::get_dns_configuration_data(dns_operations.client.clone());
        let mut saved_configs = unwrap!(config_data);
        saved_configs.push(dns_configuration::DnsConfiguration {
                               long_name: dns_name.clone(),
                               encryption_keypair: (messaging_keypair.0,
                                                    messaging_keypair.1.clone()),
                           });
        unwrap!(dns_configuration::write_dns_configuration_data(dns_operations.client.clone(),
                                                                &saved_configs));
        unwrap!(dns_operations.delete_dns(&dns_name, &secret_signing_key));

        // Trying to delete a second time should error again.
        match dns_operations.delete_dns(&dns_name, &secret_signing_key) {
            Ok(x) => {
................................................................................

        // Re-registering by the same client is not allowed again (check that we're back in a sane
        // state).
        match dns_operations.register_dns(dns_name.clone(),
                                          &messaging_keypair.0,
                                          &messaging_keypair.1,
                                          &[],
                                          owners,
                                          &secret_signing_key,
                                          None) {
            Ok(_) => panic!("Should have been an error"),
            Err(DnsError::DnsNameAlreadyRegistered) => (),
            Err(error) => panic!("{:?}", error),
        }

................................................................................
        // Re-registering by a different new_client is not allowed
        {
            let new_client = Arc::new(Mutex::new(unwrap!(test_utils::get_client())));
            let dns_operations = unwrap!(DnsOperations::new(new_client.clone()));

            let messaging_keypair = box_::gen_keypair();
            let mut owners = BTreeSet::new();
            owners.insert(*unwrap!(unwrap!(new_client.lock()).get_public_signing_key()));

            let secret_signing_key = unwrap!(unwrap!(new_client.lock()).get_secret_signing_key())
                .clone();
            match dns_operations.register_dns(dns_name.clone(),
                                              &messaging_keypair.0,
                                              &messaging_keypair.1,
                                              &[],
                                              owners,
                                              &secret_signing_key,
                                              None) {
                Ok(_) => panic!("Should have been an error"),
                Err(DnsError::DnsNameAlreadyRegistered) => (),
                Err(error) => panic!("{:?}", error),
            }
        }
................................................................................
                                ("bad-ass".to_string(),
                                 DirectoryKey::new(XorName([123; XOR_NAME_LEN]),
                                                   15000,
                                                   false,
                                                   AccessLevel::Public))];

        let mut owners = BTreeSet::new();
        owners.insert(*unwrap!(unwrap!(client.lock()).get_public_signing_key()));

        let secret_signing_key = unwrap!(unwrap!(client.lock()).get_secret_signing_key()).clone();

        // Register
        unwrap!(dns_operations.register_dns(dns_name.clone(),
                                            &messaging_keypair.0,
                                            &messaging_keypair.1,
                                            &services,
                                            owners,
                                            &secret_signing_key,
                                            None));

        // Get all dns-names
        let dns_records_vec = unwrap!(dns_operations.get_all_registered_names());
        assert_eq!(dns_records_vec.len(), 1);

................................................................................
        let unregistered_client =
            Arc::new(Mutex::new(unwrap!(Client::create_unregistered_client())));
        let dns_operations_unregistered = DnsOperations::new_unregistered(unregistered_client);

        // Get all services for a dns-name
        let services_vec = unwrap!(dns_operations_unregistered.get_all_services(&dns_name, None));
        assert_eq!(services.len(), services_vec.len());
        assert!(services
                    .iter()
                    .all(|&(ref a, _)| services_vec.iter().any(|b| *a == **b)));

        assert!(dns_operations
                    .get_service_home_directory_key(&"bogus".to_string(),
                                                    &services[0].0,
                                                    None)
                    .is_err());

        // Get information about a service - the home-directory and its type
        let home_dir_key_result =
            dns_operations_unregistered.get_service_home_directory_key(&dns_name,
                                                                       &services[1].0,
                                                                       None);
        let home_dir_key = unwrap!(home_dir_key_result);
................................................................................
                                              &secret_signing_key,
                                              None));
        ::std::thread::sleep(::std::time::Duration::from_secs(1));

        // Get all services
        let services_vec = unwrap!(dns_operations_unregistered.get_all_services(&dns_name, None));
        assert_eq!(services.len(), services_vec.len());
        assert!(services
                    .iter()
                    .all(|&(ref a, _)| services_vec.iter().any(|b| *a == **b)));

        // Try to enquire about a deleted service
        match dns_operations_unregistered.get_service_home_directory_key(&dns_name,
                                                                         &removed_service.0,
                                                                         None) {
            Ok(_) => panic!("Should have been an error"),
            Err(DnsError::ServiceNotFound) => (),
................................................................................
                                           services[services_size - 1].clone(),
                                           &secret_signing_key,
                                           None));

        // Get all services
        let services_vec = unwrap!(dns_operations_unregistered.get_all_services(&dns_name, None));
        assert_eq!(services.len(), services_vec.len());
        assert!(services
                    .iter()
                    .all(|&(ref a, _)| services_vec.iter().any(|b| *a == **b)));
    }

    #[test]
    #[cfg(feature = "use-mock-routing")]
    fn register_and_delete_dns_internal_error_recovery() {
        use core::errors::CoreError;
        use nfs::errors::NfsError;
................................................................................
        unwrap!(maidsafe_utilities::log::init(true));

        let client = Arc::new(Mutex::new(unwrap!(test_utils::get_client())));
        let dns_operations = unwrap!(DnsOperations::new(client.clone()));
        let dns_name = unwrap!(generate_random_string(10));
        let messaging_keypair = box_::gen_keypair();
        let mut owners = BTreeSet::new();
        owners.insert(*unwrap!(unwrap!(client.lock()).get_public_signing_key()));
        let secret_signing_key = unwrap!(unwrap!(client.lock()).get_secret_signing_key()).clone();

        // Limit of `Some(2)` would prevent the mutation to happen. We want one
        // `Mutation` exactly at this point
        unwrap!(client.lock()).set_network_limits(Some(3));

        info!("Fail to register the name");
................................................................................
                                          &messaging_keypair.0,
                                          &messaging_keypair.1,
                                          &[],
                                          owners.clone(),
                                          &secret_signing_key,
                                          None) {
            Err(DnsError::NfsError(NfsError::CoreError(CoreError::GetFailure {
                                                           reason: GetError::NetworkOther(ref s), ..
                                                       }))) if s == "Max operations exhausted" => {
                ()
            }
            Ok(()) => panic!("Operation unexpectedly had succeed"),
            Err(e) => panic!("Unexpected error {:?}", e),
        }

        // Remove artificial network failure
        unwrap!(client.lock()).set_network_limits(None);

................................................................................
                                            &secret_signing_key,
                                            None));

        info!("Delete with simulated failure");
        unwrap!(client.lock()).set_network_limits(Some(5));
        match dns_operations.delete_dns(&dns_name, &secret_signing_key) {
            Err(DnsError::NfsError(NfsError::CoreError(CoreError::GetFailure {
                                                           reason: GetError::NetworkOther(ref s), ..
                                                       }))) if s == "Max operations exhausted" => {
                ()
            }
            Ok(()) => panic!("Operation unexpectedly had succeed"),
            Err(e) => panic!("Unexpected error {:?}", e),
        }

        // Remove artificial network failure
        unwrap!(client.lock()).set_network_limits(None);