Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions scripts/observatory.certificate.mjs
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
#!/usr/bin/env node

import { fromNullable, isNullish } from '@dfinity/utils';
import { nextArg } from '@junobuild/cli-tools';
import { observatoryActorIC, observatoryActorLocal } from './actor.mjs';
import { targetMainnet } from './utils.mjs';

const fromBigIntNanoSeconds = (nanoseconds) => new Date(Number(nanoseconds / 1_000_000n));

const getGoogleCertificate = async (mainnet) => {
const getGoogleCertificate = async ({ mainnet, provider: cmdProvider }) => {
const { get_openid_certificate } = await (mainnet
? observatoryActorIC()
: observatoryActorLocal());

const certificate = await get_openid_certificate({ provider: { Google: null } });
const provider = cmdProvider === 'github' ? { GitHub: null } : { Google: null };

console.log('📥 Google certificate:', certificate);
const certificate = await get_openid_certificate({ provider });

console.log(`📥 ${cmdProvider} certificate:`, certificate);

const cert = fromNullable(certificate);
if (isNullish(cert)) {
Expand All @@ -25,4 +28,12 @@ const getGoogleCertificate = async (mainnet) => {

const mainnet = targetMainnet();

await getGoogleCertificate(mainnet);
const args = process.argv.slice(2);
const provider = nextArg({ args, option: '-p' }) ?? nextArg({ args, option: '--provider' });

if (!['google', 'github'].includes(provider)) {
console.log(`Provider ${provider} is not supported`);
process.exit(1);
}

await getGoogleCertificate({ mainnet, provider });
23 changes: 16 additions & 7 deletions scripts/observatory.monitoring.mjs
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
#!/usr/bin/env node

import { hasArgs } from '@junobuild/cli-tools';
import { hasArgs, nextArg } from '@junobuild/cli-tools';
import { observatoryActorIC, observatoryActorLocal } from './actor.mjs';
import { targetMainnet } from './utils.mjs';

const toggleOpenIdMonitoring = async ({ mainnet, start }) => {
const toggleOpenIdMonitoring = async ({ mainnet, provider, start }) => {
const { start_openid_monitoring, stop_openid_monitoring } = await (mainnet
? observatoryActorIC()
: observatoryActorLocal());

const args = provider === 'github' ? { GitHub: null } : { Google: null };

if (start) {
await start_openid_monitoring();
console.log('Monitoring started 🟢');
await start_openid_monitoring(args);
console.log(`Monitoring started for ${provider} 🟢`);
return;
}

await stop_openid_monitoring();
console.log('Monitoring stopped 🔴');
await stop_openid_monitoring(args);
console.log(`Monitoring stopped for ${provider} 🔴`);
};

const mainnet = targetMainnet();
Expand All @@ -35,4 +37,11 @@ if (start === true && stop === true) {
process.exit(1);
}

await toggleOpenIdMonitoring({ mainnet, start: start === true });
const provider = nextArg({ args, option: '-p' }) ?? nextArg({ args, option: '--provider' });

if (!['google', 'github'].includes(provider)) {
console.log(`Provider ${provider} is not supported`);
process.exit(1);
}

await toggleOpenIdMonitoring({ mainnet, provider, start: start === true });
6 changes: 3 additions & 3 deletions src/declarations/observatory/observatory.did.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,15 @@ export interface _SERVICE {
del_controllers: ActorMethod<[DeleteControllersArgs], undefined>;
get_notify_status: ActorMethod<[GetNotifications], NotifyStatus>;
get_openid_certificate: ActorMethod<[GetOpenIdCertificateArgs], [] | [OpenIdCertificate]>;
is_openid_monitoring_enabled: ActorMethod<[], boolean>;
is_openid_monitoring_enabled: ActorMethod<[OpenIdProvider], boolean>;
list_controllers: ActorMethod<[], Array<[Principal, Controller]>>;
notify: ActorMethod<[NotifyArgs], undefined>;
ping: ActorMethod<[NotifyArgs], undefined>;
set_controllers: ActorMethod<[SetControllersArgs], undefined>;
set_env: ActorMethod<[Env], undefined>;
set_rate_config: ActorMethod<[RateKind, RateConfig], undefined>;
start_openid_monitoring: ActorMethod<[], undefined>;
stop_openid_monitoring: ActorMethod<[], undefined>;
start_openid_monitoring: ActorMethod<[OpenIdProvider], undefined>;
stop_openid_monitoring: ActorMethod<[OpenIdProvider], undefined>;
}
export declare const idlFactory: IDL.InterfaceFactory;
export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[];
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,15 @@ export const idlFactory = ({ IDL }) => {
del_controllers: IDL.Func([DeleteControllersArgs], [], []),
get_notify_status: IDL.Func([GetNotifications], [NotifyStatus], []),
get_openid_certificate: IDL.Func([GetOpenIdCertificateArgs], [IDL.Opt(OpenIdCertificate)], []),
is_openid_monitoring_enabled: IDL.Func([], [IDL.Bool], []),
is_openid_monitoring_enabled: IDL.Func([OpenIdProvider], [IDL.Bool], []),
list_controllers: IDL.Func([], [IDL.Vec(IDL.Tuple(IDL.Principal, Controller))], []),
notify: IDL.Func([NotifyArgs], [], []),
ping: IDL.Func([NotifyArgs], [], []),
set_controllers: IDL.Func([SetControllersArgs], [], []),
set_env: IDL.Func([Env], [], []),
set_rate_config: IDL.Func([RateKind, RateConfig], [], []),
start_openid_monitoring: IDL.Func([], [], []),
stop_openid_monitoring: IDL.Func([], [], [])
start_openid_monitoring: IDL.Func([OpenIdProvider], [], []),
stop_openid_monitoring: IDL.Func([OpenIdProvider], [], [])
});
};

Expand Down
6 changes: 3 additions & 3 deletions src/declarations/observatory/observatory.factory.did.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,15 @@ export const idlFactory = ({ IDL }) => {
del_controllers: IDL.Func([DeleteControllersArgs], [], []),
get_notify_status: IDL.Func([GetNotifications], [NotifyStatus], ['query']),
get_openid_certificate: IDL.Func([GetOpenIdCertificateArgs], [IDL.Opt(OpenIdCertificate)], []),
is_openid_monitoring_enabled: IDL.Func([], [IDL.Bool], []),
is_openid_monitoring_enabled: IDL.Func([OpenIdProvider], [IDL.Bool], []),
list_controllers: IDL.Func([], [IDL.Vec(IDL.Tuple(IDL.Principal, Controller))], ['query']),
notify: IDL.Func([NotifyArgs], [], []),
ping: IDL.Func([NotifyArgs], [], []),
set_controllers: IDL.Func([SetControllersArgs], [], []),
set_env: IDL.Func([Env], [], []),
set_rate_config: IDL.Func([RateKind, RateConfig], [], []),
start_openid_monitoring: IDL.Func([], [], []),
stop_openid_monitoring: IDL.Func([], [], [])
start_openid_monitoring: IDL.Func([OpenIdProvider], [], []),
stop_openid_monitoring: IDL.Func([OpenIdProvider], [], [])
});
};

Expand Down
6 changes: 3 additions & 3 deletions src/declarations/observatory/observatory.factory.did.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,15 @@ export const idlFactory = ({ IDL }) => {
del_controllers: IDL.Func([DeleteControllersArgs], [], []),
get_notify_status: IDL.Func([GetNotifications], [NotifyStatus], ['query']),
get_openid_certificate: IDL.Func([GetOpenIdCertificateArgs], [IDL.Opt(OpenIdCertificate)], []),
is_openid_monitoring_enabled: IDL.Func([], [IDL.Bool], []),
is_openid_monitoring_enabled: IDL.Func([OpenIdProvider], [IDL.Bool], []),
list_controllers: IDL.Func([], [IDL.Vec(IDL.Tuple(IDL.Principal, Controller))], ['query']),
notify: IDL.Func([NotifyArgs], [], []),
ping: IDL.Func([NotifyArgs], [], []),
set_controllers: IDL.Func([SetControllersArgs], [], []),
set_env: IDL.Func([Env], [], []),
set_rate_config: IDL.Func([RateKind, RateConfig], [], []),
start_openid_monitoring: IDL.Func([], [], []),
stop_openid_monitoring: IDL.Func([], [], [])
start_openid_monitoring: IDL.Func([OpenIdProvider], [], []),
stop_openid_monitoring: IDL.Func([OpenIdProvider], [], [])
});
};

Expand Down
6 changes: 3 additions & 3 deletions src/observatory/observatory.did
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,13 @@ service : () -> {
get_openid_certificate : (GetOpenIdCertificateArgs) -> (
opt OpenIdCertificate,
);
is_openid_monitoring_enabled : () -> (bool);
is_openid_monitoring_enabled : (OpenIdProvider) -> (bool);
list_controllers : () -> (vec record { principal; Controller }) query;
notify : (NotifyArgs) -> ();
ping : (NotifyArgs) -> ();
set_controllers : (SetControllersArgs) -> ();
set_env : (Env) -> ();
set_rate_config : (RateKind, RateConfig) -> ();
start_openid_monitoring : () -> ();
stop_openid_monitoring : () -> ();
start_openid_monitoring : (OpenIdProvider) -> ();
stop_openid_monitoring : (OpenIdProvider) -> ();
}
14 changes: 7 additions & 7 deletions src/observatory/src/api/openid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ use crate::openid::scheduler::{
use crate::store::heap::get_certificate;
use ic_cdk_macros::update;
use junobuild_auth::openid::jwkset::types::interface::GetOpenIdCertificateArgs;
use junobuild_auth::openid::types::provider::OpenIdCertificate;
use junobuild_auth::openid::types::provider::{OpenIdCertificate, OpenIdProvider};
use junobuild_shared::ic::UnwrapOrTrap;

#[update(guard = "caller_is_admin_controller")]
fn start_openid_monitoring() {
start_openid_scheduler().unwrap_or_trap()
fn start_openid_monitoring(provider: OpenIdProvider) {
start_openid_scheduler(provider).unwrap_or_trap()
}

#[update(guard = "caller_is_admin_controller")]
fn stop_openid_monitoring() {
stop_openid_scheduler().unwrap_or_trap()
fn stop_openid_monitoring(provider: OpenIdProvider) {
stop_openid_scheduler(provider).unwrap_or_trap()
}

#[update(guard = "caller_is_admin_controller")]
fn is_openid_monitoring_enabled() -> bool {
is_openid_scheduler_enabled()
fn is_openid_monitoring_enabled(provider: OpenIdProvider) -> bool {
is_openid_scheduler_enabled(provider)
}

#[update(guard = "caller_is_not_anonymous")]
Expand Down
1 change: 1 addition & 0 deletions src/observatory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::types::state::Env;
use ic_cdk_macros::export_candid;
use junobuild_auth::openid::jwkset::types::interface::GetOpenIdCertificateArgs;
use junobuild_auth::openid::types::provider::OpenIdCertificate;
use junobuild_auth::openid::types::provider::OpenIdProvider;
use junobuild_shared::rate::types::RateConfig;
use junobuild_shared::types::interface::NotifyArgs;
use junobuild_shared::types::interface::{DeleteControllersArgs, SetControllersArgs};
Expand Down
27 changes: 14 additions & 13 deletions src/observatory/src/openid/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ use junobuild_auth::openid::types::provider::OpenIdProvider;
use std::time::Duration;

pub fn defer_restart_monitoring() {
// Early spare one timer if not enabled.
if assert_scheduler_running(&OpenIdProvider::Google).is_err() {
// Early spare one timer if no scheduler is enabled.
let enabled_count = [OpenIdProvider::Google]
.into_iter()
.filter(|provider| is_scheduler_enabled(provider))
.count();

if enabled_count == 0 {
return;
}

Expand All @@ -19,31 +24,27 @@ pub fn defer_restart_monitoring() {
}

async fn restart_monitoring() {
schedule_certificate_update(OpenIdProvider::Google, None);
for provider in [OpenIdProvider::Google] {
schedule_certificate_update(provider, None);
}
}

pub fn start_openid_scheduler() -> Result<(), String> {
let provider = OpenIdProvider::Google;

pub fn start_openid_scheduler(provider: OpenIdProvider) -> Result<(), String> {
assert_scheduler_stopped(&provider)?;

enable_scheduler(&provider);

schedule_certificate_update(OpenIdProvider::Google, None);
schedule_certificate_update(provider, None);

Ok(())
}

pub fn stop_openid_scheduler() -> Result<(), String> {
let provider = OpenIdProvider::Google;

pub fn stop_openid_scheduler(provider: OpenIdProvider) -> Result<(), String> {
assert_scheduler_running(&provider)?;

disable_scheduler(&provider)
}

pub fn is_openid_scheduler_enabled() -> bool {
let provider = OpenIdProvider::Google;

pub fn is_openid_scheduler_enabled(provider: OpenIdProvider) -> bool {
is_scheduler_enabled(&provider)
}
2 changes: 2 additions & 0 deletions src/tests/constants/auth-tests.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export const EXTERNAL_ALTERNATIVE_ORIGINS_URLS = EXTERNAL_ALTERNATIVE_ORIGINS.ma

export const LOG_SALT_INITIALIZED = 'Authentication salt initialized.';
export const LOG_SALT_ALREADY_INITIALIZED = 'Authentication salt exists. Skipping initialization.';

export const GOOGLE_OPEN_ID_PROVIDER = { Google: null };
5 changes: 3 additions & 2 deletions src/tests/specs/observatory/observatory.openid.rate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { type Actor, PocketIc } from '@dfinity/pic';
import { AnonymousIdentity } from '@icp-sdk/core/agent';
import { Ed25519KeyIdentity } from '@icp-sdk/core/identity';
import { inject } from 'vitest';
import { GOOGLE_OPEN_ID_PROVIDER } from '../../constants/auth-tests.constants';
import { CALLER_NOT_CONTROLLER_OBSERVATORY_MSG } from '../../constants/observatory-tests.constants';
import { mockCertificateDate, mockClientId } from '../../mocks/jwt.mocks';
import { makeMockGoogleOpenIdJwt } from '../../utils/jwt-tests.utils';
Expand Down Expand Up @@ -48,13 +49,13 @@ describe('Observatory > OpenId > Rate', async () => {
const loadCertificate = async () => {
const { start_openid_monitoring, stop_openid_monitoring } = actor;

await start_openid_monitoring();
await start_openid_monitoring(GOOGLE_OPEN_ID_PROVIDER);

await assertOpenIdHttpsOutcalls({ pic, jwks: mockJwks });

// We do not need to always fetch a new certificate for this suite
// We are interested in the guards
await stop_openid_monitoring();
await stop_openid_monitoring(GOOGLE_OPEN_ID_PROVIDER);
};

const setRateConfig = async (customActor?: ObservatoryActor) => {
Expand Down
15 changes: 8 additions & 7 deletions src/tests/specs/observatory/observatory.openid.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { idlFactoryObservatory, type ObservatoryActor } from '$declarations';
import { type Actor, PocketIc } from '@dfinity/pic';
import { Ed25519KeyIdentity } from '@icp-sdk/core/identity';
import { inject } from 'vitest';
import { GOOGLE_OPEN_ID_PROVIDER } from '../../constants/auth-tests.constants';
import { mockCertificateDate, mockClientId } from '../../mocks/jwt.mocks';
import { FETCH_CERTIFICATE_INTERVAL } from '../../mocks/observatory.mocks';
import { makeMockGoogleOpenIdJwt } from '../../utils/jwt-tests.utils';
Expand Down Expand Up @@ -48,15 +49,15 @@ describe('Observatory > OpenId', async () => {
it('should start openid monitoring', async () => {
const { start_openid_monitoring } = actor;

await start_openid_monitoring();
await start_openid_monitoring(GOOGLE_OPEN_ID_PROVIDER);

await assertOpenIdHttpsOutcalls({ pic, jwks: mockJwks });
});

it('should get openid monitoring enabled', async () => {
const { is_openid_monitoring_enabled } = actor;

await expect(is_openid_monitoring_enabled()).resolves.toBeTruthy();
await expect(is_openid_monitoring_enabled(GOOGLE_OPEN_ID_PROVIDER)).resolves.toBeTruthy();
});

it('should provide certificate', async () => {
Expand All @@ -66,7 +67,7 @@ describe('Observatory > OpenId', async () => {
it('should throw error if openid scheduler is already running', async () => {
const { start_openid_monitoring } = actor;

await expect(start_openid_monitoring()).rejects.toThrowError(
await expect(start_openid_monitoring(GOOGLE_OPEN_ID_PROVIDER)).rejects.toThrowError(
'OpenID scheduler for Google already running'
);
});
Expand All @@ -92,13 +93,13 @@ describe('Observatory > OpenId', async () => {

const { stop_openid_monitoring } = actor;

await expect(stop_openid_monitoring()).resolves.toBeNull();
await expect(stop_openid_monitoring(GOOGLE_OPEN_ID_PROVIDER)).resolves.toBeNull();
});

it('should get openid monitoring disabled', async () => {
const { is_openid_monitoring_enabled } = actor;

await expect(is_openid_monitoring_enabled()).resolves.toBeFalsy();
await expect(is_openid_monitoring_enabled(GOOGLE_OPEN_ID_PROVIDER)).resolves.toBeFalsy();
});

it('should still provide certificate', async () => {
Expand All @@ -124,15 +125,15 @@ describe('Observatory > OpenId', async () => {
it('should throw error if openid scheduler is already stopped', async () => {
const { stop_openid_monitoring } = actor;

await expect(stop_openid_monitoring()).rejects.toThrowError(
await expect(stop_openid_monitoring(GOOGLE_OPEN_ID_PROVIDER)).rejects.toThrowError(
'OpenID scheduler for Google is not running'
);
});

it('should restart monitoring', async () => {
const { start_openid_monitoring } = actor;

await start_openid_monitoring();
await start_openid_monitoring(GOOGLE_OPEN_ID_PROVIDER);

await assertOpenIdHttpsOutcalls({ pic, jwks: mockJwks });
});
Expand Down
Loading