• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 19012754211

02 Nov 2025 01:10PM UTC coverage: 90.677% (+0.006%) from 90.671%
19012754211

push

github

web-flow
Merge pull request #5137 from randombit/jack/clang-tidy-includes

Remove various unused includes flagged by clang-tidy misc-include-cleaner

100457 of 110786 relevant lines covered (90.68%)

12189873.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.48
/src/cli/roughtime.cpp
1
/*
2
* Roughtime
3
* (C) 2019 Nuno Goncalves <nunojpg@gmail.com>
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include "cli.h"
9

10
#if defined(BOTAN_HAS_ROUGHTIME)
11

12
   #include <botan/base64.h>
13
   #include <botan/ed25519.h>
14
   #include <botan/roughtime.h>
15
   #include <botan/internal/calendar.h>
16

17
   #include <fstream>
18
   #include <iomanip>
19

20
namespace Botan_CLI {
21

22
class RoughtimeCheck final : public Command {
23
   public:
24
      RoughtimeCheck() : Command("roughtime_check --raw-time chain-file") {}
8 ✔
25

26
      std::string group() const override { return "misc"; }
1 ✔
27

28
      std::string description() const override { return "Parse and validate Roughtime chain file"; }
1 ✔
29

30
      void go() override {
3 ✔
31
         const auto chain = Botan::Roughtime::Chain(slurp_file_as_str(get_arg("chain-file")));
6 ✔
32
         unsigned i = 0;
3 ✔
33
         for(const auto& response : chain.responses()) {
9 ✔
34
            output() << std::setw(3) << ++i << ": UTC ";
6 ✔
35
            if(flag_set("raw-time")) {
6 ✔
36
               output()
1 ✔
37
                  << Botan::Roughtime::Response::sys_microseconds64(response.utc_midpoint()).time_since_epoch().count();
1 ✔
38
            } else {
39
               output() << Botan::calendar_point(response.utc_midpoint()).to_string();
10 ✔
40
            }
41
            output() << " (+-" << Botan::Roughtime::Response::microseconds32(response.utc_radius()).count() << "us)\n";
6 ✔
42
         }
2 ✔
43
      }
2 ✔
44
};
45

46
BOTAN_REGISTER_COMMAND("roughtime_check", RoughtimeCheck);
4 ✔
47

48
class Roughtime final : public Command {
49
   public:
50
      Roughtime() :
7 ✔
51
            Command(
52
               "roughtime --raw-time --chain-file=roughtime-chain --max-chain-size=128 --check-local-clock=60 --host= --pubkey= --servers-file=") {
7 ✔
53
      }
7 ✔
54

55
      std::string help_text() const override {
×
56
         return Command::help_text() + R"(
×
57

58
--servers-file=<filename>
59
   List of servers that will queried in sequence.
60

61
   File contents syntax:
62
      <name> <key type> <base 64 encoded public key> <protocol> <host:port>
63

64
   Example servers:
65
      Cloudflare-Roughtime ed25519 0GD7c3yP8xEc4Zl2zeuN2SlLvDVVocjsPSL8/Rl/7zg= udp roughtime.cloudflare.com:2003
66
      Google-Sandbox-Roughtime ed25519 etPaaIxcBMY1oUeGpwvPMCJMwlRVNxv51KK/tktoJTQ= udp roughtime.sandbox.google.com:2002
67

68
--chain-file=<filename>
69
   Successful queries are appended to this file.
70
   If limit of --max-chain-size records is reached, the oldest records are truncated.
71
   This queries records can be replayed using command roughtime_check <chain-file>.
72

73
   File contents syntax:
74
      <key type> <base 64 encoded public key> <base 64 encoded blind or nonce> <base 64 encoded server response>
75
)";
76
      }
77

78
      std::string group() const override { return "misc"; }
1 ✔
79

80
      std::string description() const override { return "Retrieve time from Roughtime server"; }
1 ✔
81

82
      void query(std::unique_ptr<Botan::Roughtime::Chain>& chain,
5 ✔
83
                 const size_t max_chain_size,
84
                 const std::string& address,
85
                 const Botan::Ed25519_PublicKey& public_key) {
86
         Botan::Roughtime::Nonce nonce{};
5 ✔
87
         Botan::Roughtime::Nonce blind{};
5 ✔
88
         if(chain) {
5 ✔
89
            blind = Botan::Roughtime::Nonce(rng());
3 ✔
90
            nonce = chain->next_nonce(blind);
3 ✔
91
         } else {
92
            nonce = Botan::Roughtime::Nonce(rng());
2 ✔
93
         }
94
         const auto response_raw = Botan::Roughtime::online_request(address, nonce, std::chrono::seconds(5));
5 ✔
95
         const auto response = Botan::Roughtime::Response::from_bits(response_raw, nonce);
5 ✔
96
         if(flag_set("raw-time")) {
5 ✔
97
            output()
1 ✔
98
               << "UTC "
1 ✔
99
               << Botan::Roughtime::Response::sys_microseconds64(response.utc_midpoint()).time_since_epoch().count();
1 ✔
100
         } else {
101
            output() << "UTC " << Botan::calendar_point(response.utc_midpoint()).to_string();
8 ✔
102
         }
103
         output() << " (+-" << Botan::Roughtime::Response::microseconds32(response.utc_radius()).count() << "us)";
5 ✔
104
         if(!response.validate(public_key)) {
5 ✔
105
            error_output() << "ERROR: Public key does not match!\n";
1 ✔
106
            set_return_code(1);
1 ✔
107
            return;
108
         }
109
         const auto tolerance = get_arg_sz("check-local-clock");
4 ✔
110
         if(tolerance > 0) {
4 ✔
111
            const auto now = std::chrono::system_clock::now();
1 ✔
112
            const auto diff_abs =
1 ✔
113
               now >= response.utc_midpoint() ? now - response.utc_midpoint() : response.utc_midpoint() - now;
1 ✔
114
            if(diff_abs > (response.utc_radius() + std::chrono::seconds(tolerance))) {
1 ✔
115
               error_output() << "ERROR: Local clock mismatch\n";
1 ✔
116
               set_return_code(1);
1 ✔
117
               return;
1 ✔
118
            }
119
            output() << " Local clock match";
×
120
         }
121
         if(chain) {
3 ✔
122
            chain->append({response_raw, public_key, blind}, max_chain_size);
3 ✔
123
         }
124
         output() << '\n';
3 ✔
125
      }
5 ✔
126

127
      void go() override {
6 ✔
128
         const auto max_chain_size = get_arg_sz("max-chain-size");
6 ✔
129
         const auto chain_file = get_arg("chain-file");
6 ✔
130
         const auto servers_file = get_arg_or("servers-file", "");
12 ✔
131
         const auto host = get_arg_or("host", "");
12 ✔
132
         const auto pk = get_arg_or("pubkey", "");
12 ✔
133

134
         std::unique_ptr<Botan::Roughtime::Chain> chain;
6 ✔
135
         if(!chain_file.empty() && max_chain_size >= 1) {
6 ✔
136
            try {
4 ✔
137
               chain = std::make_unique<Botan::Roughtime::Chain>(slurp_file_as_str(chain_file));
6 ✔
138
            } catch(const CLI_IO_Error&) {
2 ✔
139
               // file is to still be created
140
               chain = std::make_unique<Botan::Roughtime::Chain>();
4 ✔
141
            }
2 ✔
142
         }
143

144
         const bool from_servers_file = !servers_file.empty();
6 ✔
145
         const bool from_host_and_pk = !host.empty() && !pk.empty();
6 ✔
146
         if(from_servers_file == from_host_and_pk) {
6 ✔
147
            error_output() << "Please specify either --servers-file or --host and --pubkey\n";
1 ✔
148
            set_return_code(1);
1 ✔
149
            return;
1 ✔
150
         }
151

152
         if(!servers_file.empty()) {
5 ✔
153
            const auto servers = Botan::Roughtime::servers_from_str(slurp_file_as_str(servers_file));
3 ✔
154

155
            for(const auto& s : servers) {
6 ✔
156
               output() << std::setw(25) << std::left << s.name() << ": ";
3 ✔
157
               for(const auto& a : s.addresses()) {
3 ✔
158
                  try {
3 ✔
159
                     query(chain, max_chain_size, a, s.public_key());
3 ✔
160
                     break;
161
                  } catch(const std::exception& ex)  //network error, try next address
×
162
                  {
163
                     error_output() << ex.what() << '\n';
×
164
                  }
×
165
               }
166
            }
167

168
         } else {
3 ✔
169
            query(chain, max_chain_size, host, Botan::Ed25519_PublicKey(Botan::base64_decode(pk)));
4 ✔
170
         }
171

172
         if(chain) {
5 ✔
173
            std::ofstream out(chain_file);
3 ✔
174
            out << chain->to_string();
6 ✔
175
         }
3 ✔
176
      }
6 ✔
177
};
178

179
BOTAN_REGISTER_COMMAND("roughtime", Roughtime);
7 ✔
180

181
}  // namespace Botan_CLI
182

183
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc