Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MissionAuthorization APIs #111

Merged
merged 3 commits into from
Mar 5, 2024
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
73 changes: 50 additions & 23 deletions api/lib/api/mission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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())),
Expand All @@ -67,81 +71,98 @@ export default class {
return encodeURIComponent(name.trim())
}

#headers(opts?: Static<typeof MissionOptions>): 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<typeof MissionOptions>) {
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<typeof MissionOptions>) {
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<typeof AttachContentsInput>) {
async attachContents(name: string, body: Static<typeof AttachContentsInput>, opts?: Static<typeof MissionOptions>) {
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
});
}

/**
* Upload a Mission Package
*/
async upload(name: string, creatorUid: string, body: Readable) {
async upload(name: string, creatorUid: string, body: Readable, opts?: Static<typeof MissionOptions>) {
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
});
}

/**
* Return UIDs associated with any subscribed users
*/
async subscriptions(name: string): Promise<TAKList<Static<typeof MissionSubscriber>>> {
async subscriptions(name: string, opts?: Static<typeof MissionOptions>): Promise<TAKList<Static<typeof MissionSubscriber>>> {
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<TAKList<any>> {
async subscriptionRoles(name: string, opts?: Static<typeof MissionOptions>): Promise<TAKList<any>> {
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<Static<typeof MissionSubscriber>> {
async subscription(name: string, opts?: Static<typeof MissionOptions>): Promise<Static<typeof MissionSubscriber>> {
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;
Expand All @@ -158,12 +179,13 @@ export default class {
end?: string;

[key: string]: unknown;
}) {
}, opts?: Static<typeof MissionOptions>) {
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),
});
}

Expand All @@ -174,12 +196,13 @@ export default class {
uid: string;

[key: string]: unknown;
}) {
}, opts?: Static<typeof MissionOptions>) {
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),
});
}

Expand All @@ -191,12 +214,13 @@ export default class {
disconnectOnly?: string;

[key: string]: unknown;
}) {
}, opts?: Static<typeof MissionOptions>) {
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),
});
}

Expand Down Expand Up @@ -230,12 +254,13 @@ export default class {
end?: string;

[key: string]: unknown;
}): Promise<Static<typeof Mission>> {
}, opts?: Static<typeof MissionOptions>): Promise<Static<typeof Mission>> {
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<Static <typeof Mission>> = 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}`);
Expand All @@ -254,15 +279,16 @@ export default class {
end?: string;

[key: string]: unknown;
}): Promise<Static<typeof Mission>> {
}, opts?: Static<typeof MissionOptions>): Promise<Static<typeof Mission>> {
name = name.trim();
const url = new URL(`/Marti/api/missions/${this.#encodeName(name)}`, this.api.url);
console.error(url)

for (const q in query) url.searchParams.append(q, String(query[q]));

const missions: TAKList<Static<typeof Mission>> = 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}`);
Expand Down Expand Up @@ -308,12 +334,13 @@ export default class {
deepDelete?: string;

[key: string]: unknown;
}) {
}, opts?: Static<typeof MissionOptions>) {
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),
});
}
}
8 changes: 6 additions & 2 deletions api/lib/data-mission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
6 changes: 3 additions & 3 deletions api/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions api/routes/data-asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
});
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions api/routes/layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
});
}

Expand Down
Loading