nocal account connect microsoft runs the PKCE browser flow, reads /me, upserts the deterministic account row, and persists tokens to Secret Service as the final connected-state gate. Account IDs are hashed from the remote subject so reconnect is idempotent, and a secret-store failure leaves the same coherent state as a disconnect. Ships a placeholder client ID with NOCAL_MICROSOFT_CLIENT_ID override until a real Entra registration exists.
78 lines
3.0 KiB
C++
78 lines
3.0 KiB
C++
#pragma once
|
|
|
|
#include "nocal/storage/sync_cache.hpp"
|
|
#include "nocal/sync/http.hpp"
|
|
|
|
#include <cstdint>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <string_view>
|
|
|
|
namespace nocal::sync {
|
|
|
|
// Per-operation credentials for Microsoft Graph. The adapter never retains the
|
|
// access token after the public operation returns.
|
|
struct MicrosoftGraphCredentials {
|
|
std::string account_id;
|
|
std::string access_token;
|
|
};
|
|
|
|
// A half-open UTC calendar window. Values are Unix epoch microseconds and are
|
|
// serialized canonically before they become part of a durable checkpoint.
|
|
struct MicrosoftGraphWindow {
|
|
std::int64_t start_epoch_microseconds{0};
|
|
std::int64_t end_epoch_microseconds{0};
|
|
};
|
|
|
|
class MicrosoftGraphError : public std::runtime_error {
|
|
public:
|
|
using std::runtime_error::runtime_error;
|
|
};
|
|
|
|
// Validated /me identity. Fetched without persisting anything so account
|
|
// connect can derive the deterministic local account id before any cache write.
|
|
struct MicrosoftGraphIdentity {
|
|
std::string remote_subject;
|
|
std::string display_name;
|
|
};
|
|
|
|
// Read-only Microsoft Graph v1.0 synchronization. Calendar discovery covers
|
|
// every calendar returned by /me/calendars. Stable v1.0 event delta is used for
|
|
// the primary calendar and complete calendarView reconciliation for secondary
|
|
// calendars; this class does not call beta or undocumented delta routes.
|
|
class MicrosoftGraphSync {
|
|
public:
|
|
MicrosoftGraphSync(HttpTransport& transport, storage::SyncCache& cache);
|
|
|
|
// Requires delegated User.Read. Reads /me and returns the validated
|
|
// identity without touching the cache; the access token is not retained.
|
|
[[nodiscard]] MicrosoftGraphIdentity fetch_identity(std::string_view access_token) const;
|
|
|
|
// Requires delegated User.Read. A complete and validated /me response is
|
|
// persisted atomically; failures leave the cached account unchanged.
|
|
storage::CachedAccount refresh_account(const MicrosoftGraphCredentials& credentials);
|
|
|
|
// Requires delegated Calendars.Read. Pagination is completed before the
|
|
// cache listing is replaced, so a partial listing never deactivates data.
|
|
void refresh_calendars(const MicrosoftGraphCredentials& credentials);
|
|
|
|
// Requires delegated Calendars.Read. Each validated page and its opaque
|
|
// next/delta URL are committed in one cache transaction. A later-page
|
|
// failure therefore resumes from the last committed cursor. Only HTTPS
|
|
// continuations on graph.microsoft.com are accepted.
|
|
void sync_primary_calendar_window(const MicrosoftGraphCredentials& credentials,
|
|
const MicrosoftGraphWindow& window);
|
|
|
|
// Reads every page of the documented Graph v1.0 calendarView for one
|
|
// active, non-primary calendar. The cache window is replaced only after the
|
|
// listing completes, so a failed or malformed page leaves it unchanged.
|
|
void sync_secondary_calendar_window(const MicrosoftGraphCredentials& credentials,
|
|
std::string calendar_id, const MicrosoftGraphWindow& window);
|
|
|
|
private:
|
|
HttpTransport& transport_;
|
|
storage::SyncCache& cache_;
|
|
};
|
|
|
|
} // namespace nocal::sync
|