Sneaky jira tweaks

This commit is contained in:
Will Hunt 2021-11-30 19:34:46 +00:00
parent 8ab5505a0f
commit 945514bcbc
6 changed files with 31 additions and 21 deletions

View File

@ -179,8 +179,10 @@ export class GitLabIssueConnection implements IConnection {
if (ev.content.body === '!sync') {
// Sync data.
// return this.syncIssueState();
return true;
}
await this.onMatrixIssueComment(ev);
return true;
}
public toString() {

View File

@ -13,9 +13,10 @@ export interface IConnection {
onEvent?: (ev: MatrixEvent<unknown>) => Promise<void>;
/**
* When a room gets a message event
* When a room gets a message event.
* @returns Was the message handled
*/
onMessageEvent?: (ev: MatrixEvent<MatrixMessageContent>) => Promise<void>;
onMessageEvent?: (ev: MatrixEvent<MatrixMessageContent>) => Promise<boolean>;
onIssueCreated?: (ev: IssuesOpenedEvent) => Promise<void>;

View File

@ -7,13 +7,13 @@ import { JiraIssueEvent, JiraIssueUpdatedEvent } from "../Jira/WebhookTypes";
import { FormatUtil } from "../FormatUtil";
import markdownit from "markdown-it";
import { generateJiraWebLinkFromIssue } from "../Jira";
import { JiraIssue, JiraProject } from "../Jira/Types";
import { JiraProject } from "../Jira/Types";
import { botCommand, BotCommands, compileBotCommands } from "../BotCommands";
import { MatrixMessageContent } from "../MatrixEvent";
import { CommandConnection } from "./CommandConnection";
import { start } from "repl";
import { UserTokenStore } from "../UserTokenStore";
import { CommandError, NotLoggedInError } from "../errors";
import JiraApi from "jira-client";
type JiraAllowedEventsNames = "issue.created";
const JiraAllowedEvents: JiraAllowedEventsNames[] = ["issue.created"];
@ -159,11 +159,14 @@ export class JiraProjectConnection extends CommandConnection implements IConnect
if (!jiraClient) {
throw new NotLoggedInError();
}
const resource = (await jiraClient.getAccessibleResources()).find((r) => new URL(r.url).origin === this.instanceOrigin);
if (!resource) {
throw new CommandError("No-resource", "You do not have permission to create issues for this JIRA org");
if (!this.projectUrl) {
throw new CommandError("No-resource-origin", "Room is configured with an ID and not a URL, cannot determine correct JIRA client");
}
return jiraClient.getClientForResource(resource);
const jiraProjectClient = await jiraClient.getClientForUrl(this.projectUrl);
if (!jiraProjectClient) {
throw new CommandError("No-resource", "You do not have permission to manage issues for this JIRA org");
}
return jiraProjectClient;
}
@botCommand("create", "Create an issue for this project", ["type", "title"], ["description", "labels"], true)
@ -183,7 +186,7 @@ export class JiraProjectConnection extends CommandConnection implements IConnect
throw new CommandError("invalid-issuetype", `You must specify a valid issue type (one of ${content}). E.g. ${this.commandPrefix} create ${project.issueTypes[0].name}`);
}
log.info(`Creating new issue on behalf of ${userId}`);
let result: any;
let result: JiraApi.JsonResponse;
try {
result = await api.addNewIssue({
//update: {},

View File

@ -4,7 +4,9 @@ import JiraApi, { SearchUserOptions } from 'jira-client';
import QuickLRU from "@alloc/quick-lru";
import { JiraAccount, JiraAPIAccessibleResource, JiraIssue, JiraOAuthResult, JiraProject } from './Types';
import { BridgeConfigJira } from '../Config/Config';
import LogWrapper from '../LogWrapper';
const log = new LogWrapper("JiraClient");
const ACCESSIBLE_RESOURCE_CACHE_LIMIT = 100;
const ACCESSIBLE_RESOURCE_CACHE_TTL_MS = 60000;
@ -13,11 +15,11 @@ export class HookshotJiraApi extends JiraApi {
super(options);
}
async getProject(projectIdOrKey: string) {
async getProject(projectIdOrKey: string): Promise<JiraProject> {
return await super.getProject(projectIdOrKey) as JiraProject;
}
async getIssue(issueIdOrKey: string) {
async getIssue(issueIdOrKey: string): Promise<JiraIssue> {
const res = await axios.get<JiraIssue>(`https://api.atlassian.com/${this.options.base}/rest/api/3/issue/${issueIdOrKey}`, {
headers: {
Authorization: `Bearer ${this.options.bearer}`
@ -60,6 +62,7 @@ export class JiraClient {
// Existing failed promise, break out and try again.
JiraClient.resourceCache.delete(this.bearer);
}
await this.checkTokenAge();
const promise = (async () => {
const res = await axios.get(`https://api.atlassian.com/oauth/token/accessible-resources`, {
headers: {
@ -74,26 +77,28 @@ export class JiraClient {
}
async checkTokenAge() {
console.log("checkTokenAge:", this.oauth2State);
if (this.oauth2State.expires_in + 60000 > Date.now()) {
return;
}
log.info(`Refreshing oauth token`);
// Refresh the token
const res = await axios.post<unknown, JiraOAuthResult>(`https://api.atlassian.com/oauth/token`, {
const res = await axios.post(`https://api.atlassian.com/oauth/token`, {
grant_type: "refresh_token",
client_id: this.config.oauth.client_id,
client_secret: this.config.oauth.client_secret,
refresh_token: this.oauth2State.refresh_token,
});
res.expires_in += Date.now() + (res.expires_in * 1000);
this.oauth2State = res;
const data = res.data as JiraOAuthResult;
data.expires_in += Date.now() + (data.expires_in * 1000);
this.oauth2State = data;
this.onTokenRefreshed(this.oauth2State);
}
async getClientForName(name: string) {
const resources = await this.getAccessibleResources();
const resource = resources.find((res) => res.name === name);
await this.checkTokenAge();
async getClientForUrl(url: URL) {
const resource = (await this.getAccessibleResources()).find((r) => new URL(r.url).origin === url.origin);
if (!resource) {
throw Error('User does not have access to this resource');
return null;
}
return this.getClientForResource(resource);
}

View File

@ -69,7 +69,7 @@ export interface JiraIssue {
}
export interface JiraOAuthResult {
state: string;
state?: string;
access_token: string;
refresh_token: string;
expires_in: number;

View File

@ -3,7 +3,6 @@ import { GitLabClient } from "./Gitlab/Client";
import { Intent } from "matrix-bot-sdk";
import { promises as fs } from "fs";
import { publicEncrypt, privateDecrypt } from "crypto";
import JiraApi from 'jira-client';
import LogWrapper from "./LogWrapper";
import { JiraClient } from "./Jira/Client";
import { JiraOAuthResult } from "./Jira/Types";