react-native-intune 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +27 -0
- package/NOTICE +49 -0
- package/README.md +164 -0
- package/RNIntune.podspec +69 -0
- package/android/build.gradle +152 -0
- package/android/consumer-rules.pro +28 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/reactnativeintune/RNIntuneAuth.kt +330 -0
- package/android/src/main/java/com/reactnativeintune/RNIntuneAuthCallback.kt +195 -0
- package/android/src/main/java/com/reactnativeintune/RNIntuneConfig.kt +63 -0
- package/android/src/main/java/com/reactnativeintune/RNIntuneEventQueue.kt +50 -0
- package/android/src/main/java/com/reactnativeintune/RNIntuneModule.kt +752 -0
- package/android/src/main/java/com/reactnativeintune/RNIntuneMsalConfig.kt +78 -0
- package/android/src/main/java/com/reactnativeintune/RNIntuneNotifications.kt +187 -0
- package/android/src/main/java/com/reactnativeintune/RNIntunePackage.kt +33 -0
- package/android/src/main/java/com/reactnativeintune/RNIntunePolicy.kt +108 -0
- package/android/src/main/java/com/reactnativeintune/RNIntuneReset.kt +85 -0
- package/android/src/main/java/com/reactnativeintune/RNIntuneResetJournal.kt +140 -0
- package/app.plugin.js +10 -0
- package/ios/RNIntune.h +20 -0
- package/ios/RNIntune.mm +467 -0
- package/ios/RNIntuneAuth.h +121 -0
- package/ios/RNIntuneAuth.m +390 -0
- package/ios/RNIntuneCore.h +150 -0
- package/ios/RNIntuneCore.m +535 -0
- package/ios/RNIntuneDelegates.h +70 -0
- package/ios/RNIntuneDelegates.m +268 -0
- package/ios/RNIntunePendingRequests.h +57 -0
- package/ios/RNIntunePendingRequests.m +230 -0
- package/ios/RNIntunePlistGuard.h +37 -0
- package/ios/RNIntunePlistGuard.m +147 -0
- package/ios/RNIntunePolicy.h +25 -0
- package/ios/RNIntunePolicy.m +112 -0
- package/ios/RNIntuneReset.h +34 -0
- package/ios/RNIntuneReset.m +93 -0
- package/ios/RNIntuneResetJournal.h +69 -0
- package/ios/RNIntuneResetJournal.m +106 -0
- package/lib/module/NativeIntune.js +20 -0
- package/lib/module/NativeIntune.js.map +1 -0
- package/lib/module/api/auth.js +66 -0
- package/lib/module/api/auth.js.map +1 -0
- package/lib/module/api/enrollment.js +104 -0
- package/lib/module/api/enrollment.js.map +1 -0
- package/lib/module/api/events.js +50 -0
- package/lib/module/api/events.js.map +1 -0
- package/lib/module/api/lifecycle.js +73 -0
- package/lib/module/api/lifecycle.js.map +1 -0
- package/lib/module/api/policy.js +23 -0
- package/lib/module/api/policy.js.map +1 -0
- package/lib/module/api/tokenProvider.js +80 -0
- package/lib/module/api/tokenProvider.js.map +1 -0
- package/lib/module/index.js +82 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/internal/decode.js +153 -0
- package/lib/module/internal/decode.js.map +1 -0
- package/lib/module/internal/emitter.js +15 -0
- package/lib/module/internal/emitter.js.map +1 -0
- package/lib/module/internal/errors.js +32 -0
- package/lib/module/internal/errors.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +143 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeIntune.d.ts +120 -0
- package/lib/typescript/src/NativeIntune.d.ts.map +1 -0
- package/lib/typescript/src/api/auth.d.ts +37 -0
- package/lib/typescript/src/api/auth.d.ts.map +1 -0
- package/lib/typescript/src/api/enrollment.d.ts +54 -0
- package/lib/typescript/src/api/enrollment.d.ts.map +1 -0
- package/lib/typescript/src/api/events.d.ts +24 -0
- package/lib/typescript/src/api/events.d.ts.map +1 -0
- package/lib/typescript/src/api/lifecycle.d.ts +33 -0
- package/lib/typescript/src/api/lifecycle.d.ts.map +1 -0
- package/lib/typescript/src/api/policy.d.ts +14 -0
- package/lib/typescript/src/api/policy.d.ts.map +1 -0
- package/lib/typescript/src/api/tokenProvider.d.ts +18 -0
- package/lib/typescript/src/api/tokenProvider.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +67 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/internal/decode.d.ts +48 -0
- package/lib/typescript/src/internal/decode.d.ts.map +1 -0
- package/lib/typescript/src/internal/emitter.d.ts +11 -0
- package/lib/typescript/src/internal/emitter.d.ts.map +1 -0
- package/lib/typescript/src/internal/errors.d.ts +22 -0
- package/lib/typescript/src/internal/errors.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +317 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +204 -0
- package/plugin/transforms.js +153 -0
- package/plugin/withIntune.js +320 -0
- package/scripts/cli.mjs +72 -0
- package/scripts/doctor.mjs +232 -0
- package/scripts/fetch-sdks.mjs +456 -0
- package/scripts/lib/checks.mjs +720 -0
- package/scripts/lib/project.mjs +196 -0
- package/scripts/setup.mjs +233 -0
- package/sdk-lock.json +27 -0
- package/sdk-versions.json +70 -0
- package/src/NativeIntune.ts +130 -0
- package/src/api/auth.ts +73 -0
- package/src/api/enrollment.ts +112 -0
- package/src/api/events.ts +87 -0
- package/src/api/lifecycle.ts +75 -0
- package/src/api/policy.ts +22 -0
- package/src/api/tokenProvider.ts +80 -0
- package/src/index.ts +127 -0
- package/src/internal/decode.ts +191 -0
- package/src/internal/emitter.ts +14 -0
- package/src/internal/errors.ts +43 -0
- package/src/types.ts +381 -0
package/src/api/auth.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sign-in, for `authMode: 'builtin'` — the module owns MSAL (SPEC §3).
|
|
3
|
+
*
|
|
4
|
+
* Two tokens exist and only one of them appears here: the MAM service token is acquired
|
|
5
|
+
* internally and never crosses the bridge. Everything returned by these calls is for
|
|
6
|
+
* *your* API's scopes (SPEC §3.5).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import NativeIntune from '../NativeIntune';
|
|
10
|
+
import { assertAccountId } from '../internal/errors';
|
|
11
|
+
import { toAuthAccount, toAuthResult } from '../internal/decode';
|
|
12
|
+
import { enroll } from './enrollment';
|
|
13
|
+
import type {
|
|
14
|
+
AcquireTokenParams,
|
|
15
|
+
AuthAccount,
|
|
16
|
+
AuthResult,
|
|
17
|
+
EnrollmentResult,
|
|
18
|
+
SignInParams,
|
|
19
|
+
SignOutParams,
|
|
20
|
+
} from '../types';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Uses the broker when one is present, which also gives device-wide SSO: a user already
|
|
24
|
+
* signed into Outlook usually gets a token with no prompt at all.
|
|
25
|
+
*/
|
|
26
|
+
export async function signIn(params: SignInParams = {}): Promise<AuthResult> {
|
|
27
|
+
return toAuthResult(await NativeIntune.signIn(params));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Cache-first. Rejects with `E_INTERACTION_REQUIRED` when a prompt is needed — the normal
|
|
32
|
+
* pattern is `signInSilent` first, `signIn` on that rejection.
|
|
33
|
+
*/
|
|
34
|
+
export async function signInSilent(
|
|
35
|
+
params: SignInParams = {}
|
|
36
|
+
): Promise<AuthResult> {
|
|
37
|
+
return toAuthResult(await NativeIntune.signInSilent(params));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** For your own API's scopes, after sign-in. */
|
|
41
|
+
export async function acquireToken(
|
|
42
|
+
params: AcquireTokenParams
|
|
43
|
+
): Promise<AuthResult> {
|
|
44
|
+
return toAuthResult(await NativeIntune.acquireToken(params));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Accounts with cached refresh tokens. Under single identity (SPEC §9) this holds at
|
|
49
|
+
* most one; more than one means state a reset should have cleared.
|
|
50
|
+
*/
|
|
51
|
+
export async function getAccounts(): Promise<AuthAccount[]> {
|
|
52
|
+
const accounts = await NativeIntune.getAccounts();
|
|
53
|
+
return accounts.map(toAuthAccount);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Removes the account from the MSAL cache. With `wipeIntune: true` it also runs the full
|
|
58
|
+
* reset sequence, which is what you want on logout — and which means **the process may
|
|
59
|
+
* terminate during this call on Android.**
|
|
60
|
+
*/
|
|
61
|
+
export function signOut(params: SignOutParams): Promise<void> {
|
|
62
|
+
assertAccountId(params.accountId);
|
|
63
|
+
return NativeIntune.signOut(params);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** The common path in one call. Use the primitives when you need a step in between. */
|
|
67
|
+
export async function signInAndEnroll(
|
|
68
|
+
params: SignInParams = {}
|
|
69
|
+
): Promise<{ auth: AuthResult; enrollment: EnrollmentResult }> {
|
|
70
|
+
const auth = await signIn(params);
|
|
71
|
+
const enrollment = await enroll({ accountId: auth.accountId });
|
|
72
|
+
return { auth, enrollment };
|
|
73
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enrollment, state, and the reset sequence.
|
|
3
|
+
*
|
|
4
|
+
* The theme running through all three: **the SDK reports asynchronously and the process
|
|
5
|
+
* may not survive**. Nothing here resolves from a call returning, and nothing assumes
|
|
6
|
+
* the next line will run.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import NativeIntune from '../NativeIntune';
|
|
10
|
+
import { assertAccountId } from '../internal/errors';
|
|
11
|
+
import { toEnrollmentResult, toIntuneState } from '../internal/decode';
|
|
12
|
+
import type {
|
|
13
|
+
EnrollInteractiveParams,
|
|
14
|
+
EnrollmentResult,
|
|
15
|
+
EnrollParams,
|
|
16
|
+
IntuneState,
|
|
17
|
+
ResetHandler,
|
|
18
|
+
ResetParams,
|
|
19
|
+
} from '../types';
|
|
20
|
+
|
|
21
|
+
let resetHandler: ResetHandler | null = null;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Clears the app's own local data during a reset. The module cannot do this for you — it
|
|
25
|
+
* does not know what you store or where.
|
|
26
|
+
*
|
|
27
|
+
* Registered rather than passed to `reset` because a reset can be *resumed* at launch
|
|
28
|
+
* from the journal, with no `reset` call in flight (SPEC §7).
|
|
29
|
+
*/
|
|
30
|
+
export function setResetHandler(handler: ResetHandler | null): void {
|
|
31
|
+
resetHandler = handler;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Resolves with a result for every outcome including failures — a non-success status is
|
|
36
|
+
* data, not an exception. It only rejects for programming errors.
|
|
37
|
+
*
|
|
38
|
+
* Expect seconds, and a spinner: the promise settles when the SDK reports through its
|
|
39
|
+
* delegate or notification, not when the underlying call returns.
|
|
40
|
+
*
|
|
41
|
+
* Read SPEC §8 before branching on `status`. `NotLicensed` and `NotTargeted` must not
|
|
42
|
+
* block the user; `Failed` must.
|
|
43
|
+
*/
|
|
44
|
+
export async function enroll(params: EnrollParams): Promise<EnrollmentResult> {
|
|
45
|
+
assertAccountId(params.accountId);
|
|
46
|
+
return toEnrollmentResult(
|
|
47
|
+
// '' rather than undefined: the Codegen spec has no optionals, so "not known" has to
|
|
48
|
+
// be a value the native side can recognise.
|
|
49
|
+
await NativeIntune.enroll({
|
|
50
|
+
accountId: params.accountId,
|
|
51
|
+
upn: params.upn ?? '',
|
|
52
|
+
})
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* **iOS only.** Hands the whole sign-in to the SDK: it shows its own credential screen,
|
|
58
|
+
* signs the user in, and enrolls them. No MSAL on our side, which is why this works
|
|
59
|
+
* before the built-in auth layer exists.
|
|
60
|
+
*
|
|
61
|
+
* Rejects with `E_SDK_UNAVAILABLE` on Android — `registerAccountForMAM` there always
|
|
62
|
+
* needs a token supplied by the app, so there is nothing equivalent to call.
|
|
63
|
+
*
|
|
64
|
+
* Like `enroll`, it resolves with a result for every outcome including failures.
|
|
65
|
+
*/
|
|
66
|
+
export async function enrollInteractive(
|
|
67
|
+
params: EnrollInteractiveParams = {}
|
|
68
|
+
): Promise<EnrollmentResult> {
|
|
69
|
+
return toEnrollmentResult(
|
|
70
|
+
await NativeIntune.enrollInteractive({ upn: params.upn ?? '' })
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The reconciliation primitive, and the intended way to drive this module. Call it at
|
|
76
|
+
* launch, compare against what your backend says the state should be, act on the
|
|
77
|
+
* difference. It never rejects.
|
|
78
|
+
*/
|
|
79
|
+
export async function getState(): Promise<IntuneState> {
|
|
80
|
+
return toIntuneState(await NativeIntune.getState());
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Unregisters, unenrolls, optionally wipes corporate data, and clears the runtime
|
|
85
|
+
* configuration.
|
|
86
|
+
*
|
|
87
|
+
* **The process is expected to terminate during this call on Android** (SPEC §7). Do not
|
|
88
|
+
* write code after `await reset(...)` that must run — put the continuation in the
|
|
89
|
+
* launch-time reconciliation and let the journal resume it.
|
|
90
|
+
*/
|
|
91
|
+
export async function reset(params: ResetParams): Promise<void> {
|
|
92
|
+
// The order below is SPEC §7's, and it is not the intuitive one. The unregister has to
|
|
93
|
+
// happen before anything purges the account's tokens, and on Android the process is
|
|
94
|
+
// expected to die during it — so local cleanup cannot come first, and cannot be
|
|
95
|
+
// assumed to run at all. The journal carries the sequence across that death: if the
|
|
96
|
+
// native call never returns, the next launch sees `pendingReset` and calls reset()
|
|
97
|
+
// again with reason 'resume', landing back here.
|
|
98
|
+
const state = await getState().catch(() => null);
|
|
99
|
+
const accountId = state?.enrolledAccountId ?? null;
|
|
100
|
+
|
|
101
|
+
await NativeIntune.reset(params);
|
|
102
|
+
|
|
103
|
+
// Reached only if the process survived.
|
|
104
|
+
const handler = resetHandler;
|
|
105
|
+
if (handler !== null) {
|
|
106
|
+
// Deliberately not caught: if the app cannot clear its own data, the journal stays
|
|
107
|
+
// open and the reset is retried next launch rather than being marked done.
|
|
108
|
+
await handler({ reason: params.reason, accountId });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
await NativeIntune.completeReset();
|
|
112
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed subscriptions.
|
|
3
|
+
*
|
|
4
|
+
* Every one of these can fire without the app having called anything: the SDK enrolls on
|
|
5
|
+
* its own retry schedule, an administrator can change policy, and a wipe is
|
|
6
|
+
* service-initiated. Subscribe at startup, not when you happen to be waiting (SPEC §4.4).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { EmitterSubscription } from 'react-native';
|
|
10
|
+
|
|
11
|
+
import { emitter } from '../internal/emitter';
|
|
12
|
+
import {
|
|
13
|
+
nullableStr,
|
|
14
|
+
toBrokerStatus,
|
|
15
|
+
toEnrollmentResult,
|
|
16
|
+
toPolicySnapshot,
|
|
17
|
+
toRestartReason,
|
|
18
|
+
} from '../internal/decode';
|
|
19
|
+
import type {
|
|
20
|
+
BrokerStatus,
|
|
21
|
+
EnrollmentResult,
|
|
22
|
+
IntuneEvents,
|
|
23
|
+
PolicySnapshot,
|
|
24
|
+
RestartRequest,
|
|
25
|
+
} from '../types';
|
|
26
|
+
|
|
27
|
+
function subscribe<K extends keyof IntuneEvents>(
|
|
28
|
+
event: K,
|
|
29
|
+
decode: (raw: object) => IntuneEvents[K],
|
|
30
|
+
listener: (payload: IntuneEvents[K]) => void
|
|
31
|
+
): EmitterSubscription {
|
|
32
|
+
return emitter.addListener(event, (raw: object) => listener(decode(raw)));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Also fires for the SDK's own background enrollment retries, which have no caller. */
|
|
36
|
+
export function onEnrollmentResult(
|
|
37
|
+
listener: (result: EnrollmentResult) => void
|
|
38
|
+
): EmitterSubscription {
|
|
39
|
+
return subscribe('enrollmentResult', toEnrollmentResult, listener);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** The terminal state of a reset. */
|
|
43
|
+
export function onUnenrollmentResult(
|
|
44
|
+
listener: (result: EnrollmentResult) => void
|
|
45
|
+
): EmitterSubscription {
|
|
46
|
+
return subscribe('unenrollmentResult', toEnrollmentResult, listener);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** An administrator changed policy — re-read whatever UI you gate on it. */
|
|
50
|
+
export function onPolicyChanged(
|
|
51
|
+
listener: (policy: PolicySnapshot) => void
|
|
52
|
+
): EmitterSubscription {
|
|
53
|
+
return subscribe('policyChanged', toPolicySnapshot, listener);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The user installed or removed Company Portal. */
|
|
57
|
+
export function onBrokerStatusChanged(
|
|
58
|
+
listener: (status: BrokerStatus) => void
|
|
59
|
+
): EmitterSubscription {
|
|
60
|
+
return subscribe('brokerStatusChanged', toBrokerStatus, listener);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** **Service-initiated.** Can arrive with no prior app call at all. */
|
|
64
|
+
export function onWipeRequested(
|
|
65
|
+
listener: (request: { accountId: string | null }) => void
|
|
66
|
+
): EmitterSubscription {
|
|
67
|
+
return subscribe(
|
|
68
|
+
'wipeRequested',
|
|
69
|
+
(raw) => ({
|
|
70
|
+
accountId: nullableStr((raw as Record<string, unknown>).accountId),
|
|
71
|
+
}),
|
|
72
|
+
listener
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** iOS, on first policy application. See `configure({ restartHandledByApp })`. */
|
|
77
|
+
export function onRestartRequired(
|
|
78
|
+
listener: (request: RestartRequest) => void
|
|
79
|
+
): EmitterSubscription {
|
|
80
|
+
return subscribe(
|
|
81
|
+
'restartRequired',
|
|
82
|
+
(raw) => ({
|
|
83
|
+
reason: toRestartReason((raw as Record<string, unknown>).reason),
|
|
84
|
+
}),
|
|
85
|
+
listener
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup, and the two questions worth asking before it: is the SDK usable at all, and is
|
|
3
|
+
* a broker present.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import NativeIntune from '../NativeIntune';
|
|
7
|
+
import { toBrokerStatus } from '../internal/decode';
|
|
8
|
+
import {
|
|
9
|
+
FileProtectionLevel,
|
|
10
|
+
type BrokerStatus,
|
|
11
|
+
type IntuneConfig,
|
|
12
|
+
} from '../types';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Configures the SDK for one customer tenant. Every other method rejects with
|
|
16
|
+
* `E_NOT_CONFIGURED` until this resolves.
|
|
17
|
+
*
|
|
18
|
+
* Two things it will refuse rather than paper over:
|
|
19
|
+
*
|
|
20
|
+
* - a different `tenantId` than the active one — `E_RESET_REQUIRED`, because silently
|
|
21
|
+
* reconfiguring would leave the old tenant enrolled, and the iOS runtime overrides
|
|
22
|
+
* persist across restarts so the mismatch would survive a relaunch;
|
|
23
|
+
* - an `Info.plist` that disagrees with it — `E_PLIST_CONFLICT`, see SPEC §5.1.2.
|
|
24
|
+
*/
|
|
25
|
+
export function configure(config: IntuneConfig): Promise<void> {
|
|
26
|
+
// Every optional becomes a concrete value here, so the native side never has to guess
|
|
27
|
+
// a default and the two platforms cannot drift apart on what the default was.
|
|
28
|
+
return NativeIntune.configure({
|
|
29
|
+
clientId: config.clientId,
|
|
30
|
+
tenantId: config.tenantId,
|
|
31
|
+
authority: config.authority,
|
|
32
|
+
redirectUri: config.redirectUri,
|
|
33
|
+
authMode: config.authMode ?? 'builtin',
|
|
34
|
+
verboseLogging: config.verboseLogging ?? false,
|
|
35
|
+
restartHandledByApp: config.restartHandledByApp ?? false,
|
|
36
|
+
maxFileProtectionLevel:
|
|
37
|
+
config.maxFileProtectionLevel ?? FileProtectionLevel.Complete,
|
|
38
|
+
// Throws on integration bugs that would otherwise leave data unprotected, so it is
|
|
39
|
+
// on in development and must never ship enabled.
|
|
40
|
+
strictMode: config.strictMode ?? __DEV__,
|
|
41
|
+
keychainGroupOverride: config.keychainGroupOverride ?? '',
|
|
42
|
+
telemetryEnabled: config.telemetryEnabled ?? true,
|
|
43
|
+
// Flattened because Codegen takes no nested optionals. '' means "leave the SDK's
|
|
44
|
+
// own default alone", which is not the same as a colour.
|
|
45
|
+
brandingBackground: config.branding?.background ?? '',
|
|
46
|
+
brandingForeground: config.branding?.foreground ?? '',
|
|
47
|
+
brandingAccent: config.branding?.accent ?? '',
|
|
48
|
+
brandingSecondaryBackground: config.branding?.secondaryBackground ?? '',
|
|
49
|
+
brandingSecondaryForeground: config.branding?.secondaryForeground ?? '',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* SDK linked and platform prerequisites met. Gate the whole Intune path on this so a
|
|
55
|
+
* misbuilt binary degrades instead of crashing.
|
|
56
|
+
*/
|
|
57
|
+
export function isSupported(): Promise<boolean> {
|
|
58
|
+
return NativeIntune.isSupported();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Answerable before `configure`, on purpose — the app needs it to decide whether to
|
|
63
|
+
* prompt for a broker install.
|
|
64
|
+
*
|
|
65
|
+
* A false negative here usually means a missing manifest entry rather than a missing
|
|
66
|
+
* app: `LSApplicationQueriesSchemes` on iOS, `<queries>` on Android 11+.
|
|
67
|
+
*/
|
|
68
|
+
export async function getBrokerStatus(): Promise<BrokerStatus> {
|
|
69
|
+
return toBrokerStatus(await NativeIntune.getBrokerStatus());
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Rejects with `E_NOT_NEEDED` when a broker is already present. */
|
|
73
|
+
export function openBrokerInstall(): Promise<void> {
|
|
74
|
+
return NativeIntune.openBrokerInstall();
|
|
75
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading policy, and reading the module's own state for a support bundle.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import NativeIntune from '../NativeIntune';
|
|
6
|
+
import { strRecord, toPolicySnapshot } from '../internal/decode';
|
|
7
|
+
import type { Diagnostics, PolicySnapshot } from '../types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* For adapting your own UI — hiding an export button, disabling a share sheet.
|
|
11
|
+
*
|
|
12
|
+
* **PIN prompts, screenshot blocking and encryption are enforced inside the SDK and
|
|
13
|
+
* never surface here.** Do not attempt to implement enforcement from these booleans.
|
|
14
|
+
*/
|
|
15
|
+
export async function getPolicy(): Promise<PolicySnapshot> {
|
|
16
|
+
return toPolicySnapshot(await NativeIntune.getPolicy());
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Safe to attach to a support ticket: no tokens, no UPNs. */
|
|
20
|
+
export async function getDiagnostics(): Promise<Diagnostics> {
|
|
21
|
+
return strRecord(await NativeIntune.getDiagnostics());
|
|
22
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The MAM service token bridge (SPEC §13.4).
|
|
3
|
+
*
|
|
4
|
+
* The SDK asks for this token on a background thread, including on its own retry
|
|
5
|
+
* schedule when no JS call is in flight — which is why it is a registration rather than
|
|
6
|
+
* a callback parameter on `enroll`.
|
|
7
|
+
*
|
|
8
|
+
* The token never leaves the module: the provider's answer goes to native, native hands
|
|
9
|
+
* it to the SDK, and it is never logged or returned to JS (CLAUDE.md rule 9).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import NativeIntune from '../NativeIntune';
|
|
13
|
+
import { emitter } from '../internal/emitter';
|
|
14
|
+
import { str } from '../internal/decode';
|
|
15
|
+
import type { TokenProvider, TokenRequest } from '../types';
|
|
16
|
+
|
|
17
|
+
let tokenProvider: TokenProvider | null = null;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Registers the provider for `authMode: 'external'`. Return `null` from it to say
|
|
21
|
+
* "cannot get a token right now" — the SDK treats that as needing authorization rather
|
|
22
|
+
* than as a hard failure.
|
|
23
|
+
*/
|
|
24
|
+
export function setTokenProvider(provider: TokenProvider | null): void {
|
|
25
|
+
tokenProvider = provider;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Subscribed at import time, not from `setTokenProvider`.
|
|
30
|
+
*
|
|
31
|
+
* If nothing answers, the SDK waits until the native timeout — 45s on iOS, and on
|
|
32
|
+
* Android that is a *held background thread*. Replying "no provider" immediately turns a
|
|
33
|
+
* stall into a fast, named failure.
|
|
34
|
+
*/
|
|
35
|
+
emitter.addListener('tokenRequest', (raw: object) => {
|
|
36
|
+
const r = raw as Record<string, unknown>;
|
|
37
|
+
const requestId = str(r.requestId);
|
|
38
|
+
const request: TokenRequest = {
|
|
39
|
+
resourceId: str(r.resourceId),
|
|
40
|
+
tenantId: str(r.tenantId),
|
|
41
|
+
authority: str(r.authority),
|
|
42
|
+
accountId: str(r.accountId),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const active = tokenProvider;
|
|
46
|
+
if (active === null) {
|
|
47
|
+
NativeIntune.rejectToken({
|
|
48
|
+
requestId,
|
|
49
|
+
reason:
|
|
50
|
+
"No token provider is registered. In authMode 'external' the app must call " +
|
|
51
|
+
'setTokenProvider() before enrolling.',
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const respond = async () => {
|
|
57
|
+
try {
|
|
58
|
+
const token = await active(request);
|
|
59
|
+
if (typeof token === 'string' && token.length > 0) {
|
|
60
|
+
NativeIntune.resolveToken({ requestId, token });
|
|
61
|
+
} else {
|
|
62
|
+
NativeIntune.rejectToken({
|
|
63
|
+
requestId,
|
|
64
|
+
reason: 'token provider returned no token',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
} catch (e) {
|
|
68
|
+
// The message reaches getDiagnostics and support logs, so pass the message and not
|
|
69
|
+
// the error object — a nested response body can carry a token.
|
|
70
|
+
NativeIntune.rejectToken({
|
|
71
|
+
requestId,
|
|
72
|
+
reason: e instanceof Error ? e.message : 'token provider threw',
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Nothing upstream can observe this promise: the SDK is waiting on the native side,
|
|
78
|
+
// and every path above already answers it.
|
|
79
|
+
respond().catch(() => {});
|
|
80
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API for react-native-intune. See SPEC §13 for the reference — a method that
|
|
3
|
+
* exists here but not there does not exist, and the two change in the same commit.
|
|
4
|
+
*
|
|
5
|
+
* This file is deliberately only a surface. The work is one directory down:
|
|
6
|
+
*
|
|
7
|
+
* ```
|
|
8
|
+
* src/
|
|
9
|
+
* NativeIntune.ts Codegen spec — the only file Codegen reads, deliberately loose
|
|
10
|
+
* types.ts every public type and enum
|
|
11
|
+
* api/
|
|
12
|
+
* lifecycle.ts configure, isSupported, broker presence
|
|
13
|
+
* auth.ts sign-in, tokens for your own API (authMode 'builtin')
|
|
14
|
+
* enrollment.ts enroll, getState, reset
|
|
15
|
+
* policy.ts getPolicy, getDiagnostics
|
|
16
|
+
* events.ts subscriptions
|
|
17
|
+
* tokenProvider.ts the MAM service token bridge (authMode 'external')
|
|
18
|
+
* internal/
|
|
19
|
+
* decode.ts bridge Object -> typed, with deliberate fallbacks
|
|
20
|
+
* errors.ts IntuneError and the accountId guard
|
|
21
|
+
* emitter.ts the single NativeEventEmitter
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Both import styles work and neither is preferred:
|
|
25
|
+
*
|
|
26
|
+
* ```ts
|
|
27
|
+
* import Intune from 'react-native-intune'; Intune.configure(...)
|
|
28
|
+
* import { configure } from 'react-native-intune'; configure(...)
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
export * from './types';
|
|
33
|
+
export { IntuneError } from './internal/errors';
|
|
34
|
+
|
|
35
|
+
import {
|
|
36
|
+
configure,
|
|
37
|
+
getBrokerStatus,
|
|
38
|
+
isSupported,
|
|
39
|
+
openBrokerInstall,
|
|
40
|
+
} from './api/lifecycle';
|
|
41
|
+
import {
|
|
42
|
+
acquireToken,
|
|
43
|
+
getAccounts,
|
|
44
|
+
signIn,
|
|
45
|
+
signInAndEnroll,
|
|
46
|
+
signInSilent,
|
|
47
|
+
signOut,
|
|
48
|
+
} from './api/auth';
|
|
49
|
+
import {
|
|
50
|
+
enroll,
|
|
51
|
+
enrollInteractive,
|
|
52
|
+
getState,
|
|
53
|
+
reset,
|
|
54
|
+
setResetHandler,
|
|
55
|
+
} from './api/enrollment';
|
|
56
|
+
import { getDiagnostics, getPolicy } from './api/policy';
|
|
57
|
+
import {
|
|
58
|
+
onBrokerStatusChanged,
|
|
59
|
+
onEnrollmentResult,
|
|
60
|
+
onPolicyChanged,
|
|
61
|
+
onRestartRequired,
|
|
62
|
+
onUnenrollmentResult,
|
|
63
|
+
onWipeRequested,
|
|
64
|
+
} from './api/events';
|
|
65
|
+
import { setTokenProvider } from './api/tokenProvider';
|
|
66
|
+
|
|
67
|
+
export {
|
|
68
|
+
// setup
|
|
69
|
+
configure,
|
|
70
|
+
isSupported,
|
|
71
|
+
getBrokerStatus,
|
|
72
|
+
openBrokerInstall,
|
|
73
|
+
// auth — authMode 'builtin'
|
|
74
|
+
signIn,
|
|
75
|
+
signInSilent,
|
|
76
|
+
signInAndEnroll,
|
|
77
|
+
acquireToken,
|
|
78
|
+
getAccounts,
|
|
79
|
+
signOut,
|
|
80
|
+
// enrollment and reset
|
|
81
|
+
enroll,
|
|
82
|
+
enrollInteractive,
|
|
83
|
+
getState,
|
|
84
|
+
reset,
|
|
85
|
+
setResetHandler,
|
|
86
|
+
// policy
|
|
87
|
+
getPolicy,
|
|
88
|
+
getDiagnostics,
|
|
89
|
+
// token bridge — authMode 'external'
|
|
90
|
+
setTokenProvider,
|
|
91
|
+
// events
|
|
92
|
+
onEnrollmentResult,
|
|
93
|
+
onUnenrollmentResult,
|
|
94
|
+
onPolicyChanged,
|
|
95
|
+
onWipeRequested,
|
|
96
|
+
onRestartRequired,
|
|
97
|
+
onBrokerStatusChanged,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const Intune = {
|
|
101
|
+
configure,
|
|
102
|
+
isSupported,
|
|
103
|
+
getBrokerStatus,
|
|
104
|
+
openBrokerInstall,
|
|
105
|
+
signIn,
|
|
106
|
+
signInSilent,
|
|
107
|
+
signInAndEnroll,
|
|
108
|
+
acquireToken,
|
|
109
|
+
getAccounts,
|
|
110
|
+
signOut,
|
|
111
|
+
enroll,
|
|
112
|
+
enrollInteractive,
|
|
113
|
+
getState,
|
|
114
|
+
reset,
|
|
115
|
+
setResetHandler,
|
|
116
|
+
getPolicy,
|
|
117
|
+
getDiagnostics,
|
|
118
|
+
setTokenProvider,
|
|
119
|
+
onEnrollmentResult,
|
|
120
|
+
onUnenrollmentResult,
|
|
121
|
+
onPolicyChanged,
|
|
122
|
+
onWipeRequested,
|
|
123
|
+
onRestartRequired,
|
|
124
|
+
onBrokerStatusChanged,
|
|
125
|
+
} as const;
|
|
126
|
+
|
|
127
|
+
export default Intune;
|