diff --git a/api/lib/api/mission.ts b/api/lib/api/mission.ts index fd18b93da..d0c892fce 100644 --- a/api/lib/api/mission.ts +++ b/api/lib/api/mission.ts @@ -48,6 +48,10 @@ export const MissionSubscriber = Type.Object({ }) }) +export const MissionOptions = Type.Object({ + token: Type.Optional(Type.String()) +}); + export const AttachContentsInput = Type.Object({ hashes: Type.Optional(Type.Array(Type.String())), uids: Type.Optional(Type.Array(Type.String())), @@ -67,37 +71,50 @@ export default class { return encodeURIComponent(name.trim()) } + #headers(opts?: Static): object { + if (opts.token) { + return { + MissionAuthorization: `Bearer ${opts.token}` + } + } else { + return {}; + } + } + /** * Return users associated with this mission */ - async contacts(name: string) { + async contacts(name: string, opts?: Static) { const url = new URL(`/Marti/api/missions/${this.#encodeName(name)}/contacts`, this.api.url); return await this.api.fetch(url, { - method: 'GET' + method: 'GET', + headers: this.#headers(opts) }); } /** * Remove a file from the mission */ - async detachContents(name: string, hash: string) { + async detachContents(name: string, hash: string, opts?: Static) { const url = new URL(`/Marti/api/missions/${this.#encodeName(name)}/contents`, this.api.url); url.searchParams.append('hash', hash); return await this.api.fetch(url, { method: 'DELETE', + headers: this.#headers(opts), }); } /** * Attach a file resource by hash from the TAK Server file manager */ - async attachContents(name: string, body: Static) { + async attachContents(name: string, body: Static, opts?: Static) { const url = new URL(`/Marti/api/missions/${this.#encodeName(name)}/contents`, this.api.url); return await this.api.fetch(url, { method: 'PUT', + headers: this.#headers(opts), body }); } @@ -105,12 +122,13 @@ export default class { /** * Upload a Mission Package */ - async upload(name: string, creatorUid: string, body: Readable) { + async upload(name: string, creatorUid: string, body: Readable, opts?: Static) { const url = new URL(`/Marti/api/missions/${this.#encodeName(name)}/contents/missionpackage`, this.api.url); url.searchParams.append('creatorUid', creatorUid); return await this.api.fetch(url, { method: 'PUT', + headers: this.#headers(opts), body }); } @@ -118,30 +136,33 @@ export default class { /** * Return UIDs associated with any subscribed users */ - async subscriptions(name: string): Promise>> { + async subscriptions(name: string, opts?: Static): Promise>> { const url = new URL(`/Marti/api/missions/${this.#encodeName(name)}/subscriptions`, this.api.url); return await this.api.fetch(url, { - method: 'GET' + method: 'GET', + headers: this.#headers(opts), }); } /** * Return permissions associated with any subscribed users */ - async subscriptionRoles(name: string): Promise> { + async subscriptionRoles(name: string, opts?: Static): Promise> { const url = new URL(`/Marti/api/missions/${this.#encodeName(name)}/subscriptions/roles`, this.api.url); return await this.api.fetch(url, { - method: 'GET' + method: 'GET', + headers: this.#headers(opts), }); } /** * Return permissions associated with a given mission if subscribed */ - async subscription(name: string): Promise> { + async subscription(name: string, opts?: Static): Promise> { const url = new URL(`/Marti/api/missions/${this.#encodeName(name)}/subscription`, this.api.url); const res = await this.api.fetch(url, { - method: 'GET' + method: 'GET', + headers: this.#headers(opts), }); return res.data; @@ -158,12 +179,13 @@ export default class { end?: string; [key: string]: unknown; - }) { + }, opts?: Static) { const url = new URL(`/Marti/api/missions/${this.#encodeName(name)}/subscription`, this.api.url); for (const q in query) url.searchParams.append(q, String(query[q])); return await this.api.fetch(url, { - method: 'PUT' + method: 'PUT', + headers: this.#headers(opts), }); } @@ -174,12 +196,13 @@ export default class { uid: string; [key: string]: unknown; - }) { + }, opts?: Static) { const url = new URL(`/Marti/api/missions/${this.#encodeName(name)}/subscription`, this.api.url); for (const q in query) url.searchParams.append(q, String(query[q])); return await this.api.fetch(url, { - method: 'GET' + method: 'GET', + headers: this.#headers(opts), }); } @@ -191,12 +214,13 @@ export default class { disconnectOnly?: string; [key: string]: unknown; - }) { + }, opts?: Static) { const url = new URL(`/Marti/api/missions/${this.#encodeName(name)}/subscription`, this.api.url); for (const q in query) url.searchParams.append(q, String(query[q])); return await this.api.fetch(url, { - method: 'DELETE' + method: 'DELETE', + headers: this.#headers(opts), }); } @@ -230,12 +254,13 @@ export default class { end?: string; [key: string]: unknown; - }): Promise> { + }, opts?: Static): Promise> { const url = new URL(`/Marti/api/missions/guid/${encodeURIComponent(guid)}`, this.api.url); for (const q in query) url.searchParams.append(q, String(query[q])); const missions: TAKList> = await this.api.fetch(url, { - method: 'GET' + method: 'GET', + headers: this.#headers(opts), }); if (!missions.data.length) throw new Err(404, null, `No Mission for GUID: ${guid}`); @@ -254,7 +279,7 @@ export default class { end?: string; [key: string]: unknown; - }): Promise> { + }, opts?: Static): Promise> { name = name.trim(); const url = new URL(`/Marti/api/missions/${this.#encodeName(name)}`, this.api.url); console.error(url) @@ -262,7 +287,8 @@ export default class { for (const q in query) url.searchParams.append(q, String(query[q])); const missions: TAKList> = await this.api.fetch(url, { - method: 'GET' + method: 'GET', + headers: this.#headers(opts), }); if (!missions.data.length) throw new Err(404, null, `No Mission for Name: ${name}`); @@ -308,12 +334,13 @@ export default class { deepDelete?: string; [key: string]: unknown; - }) { + }, opts?: Static) { const url = new URL(`/Marti/api/missions/${this.#encodeName(name)}`, this.api.url); for (const q in query) url.searchParams.append(q, String(query[q])); return await this.api.fetch(url, { - method: 'DELETE' + method: 'DELETE', + headers: this.#headers(opts), }); } } diff --git a/api/lib/data-mission.ts b/api/lib/data-mission.ts index 34117b8f3..dcd9b36ea 100644 --- a/api/lib/data-mission.ts +++ b/api/lib/data-mission.ts @@ -25,11 +25,15 @@ export default class DataMission { let mission; try { - mission = await api.Mission.get(data.name, {}); + mission = await api.Mission.get(data.name, {}, { + token: data.mission_token + }); //TODO Update Groups: Not supported by TAK Server at this time if (!data.mission_sync) { - await api.Mission.delete(data.name, {}); + await api.Mission.delete(data.name, {}, { + token: data.mission_token + }); return; } } catch (err) { diff --git a/api/package-lock.json b/api/package-lock.json index 43d3f019a..262f11667 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -286,9 +286,9 @@ } }, "node_modules/@aws-sdk/client-cloudformation": { - "version": "3.525.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.525.0.tgz", - "integrity": "sha512-z+IbnnVWOoS0C5s3JfheS6zxhRfJAk57zxKMD0ofTFW/eIDxhyvd12gnTWUNZch6Lz0TeeqK/hsxVvF2p0hf4A==", + "version": "3.526.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.526.0.tgz", + "integrity": "sha512-Zz6swHfQdauuCJY3j+5SUPMFWTxgpAWN3x5dl/8jdn0Q1GdiWzZ0/5+jZr83mE7ola3UUH3LP/cw1UIljJO0ZA==", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", diff --git a/api/routes/data-asset.ts b/api/routes/data-asset.ts index 9b63b2259..8eff92b72 100644 --- a/api/routes/data-asset.ts +++ b/api/routes/data-asset.ts @@ -112,6 +112,8 @@ export default async function router(schema: Schema, config: Config) { const missionContent = await api.Mission.attachContents(data.name, { hashes: [content.Hash] + }, { + token: data.mission_token }); return res.json(missionContent); @@ -244,12 +246,15 @@ export default async function router(schema: Schema, config: Config) { const file = `${req.params.asset}.${req.params.ext}`; try { if (data.mission_sync) { - let mission = await api.Mission.get(data.name, {}); + let mission = await api.Mission.get(data.name, {}, { + token: data.mission_token + }); for (const content of mission.contents) { if (content.data.name === file) { - await api.Mission.get(data.name, {}); - await api.Mission.detachContents(data.name, content.data.hash); + await api.Mission.detachContents(data.name, content.data.hash, { + token: data.mission_token + }); } } } diff --git a/api/routes/layer.ts b/api/routes/layer.ts index 35658d1ad..b6b173f4b 100644 --- a/api/routes/layer.ts +++ b/api/routes/layer.ts @@ -477,6 +477,8 @@ export default async function router(schema: Schema, config: Config) { const api = await TAKAPI.init(new URL(String(config.server.api)), new APIAuthCertificate(pooledClient.config.auth.cert, pooledClient.config.auth.key)); const missionContent = await api.Mission.attachContents(data.name, { uids: cots.map((cot) => { return cot.raw.event._attributes.uid }) + }, { + token: data.mission_token }); }