74e578c2bf
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
339 lines
15 KiB
TypeScript
339 lines
15 KiB
TypeScript
import { t } from "@lingui/macro";
|
|
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
|
import { until } from "lit-html/directives/until";
|
|
import { EventMatcherPolicyActionEnum, FlowsApi } from "authentik-api";
|
|
import "../../elements/Spinner";
|
|
import "../../elements/Expand";
|
|
import { PFSize } from "../../elements/Spinner";
|
|
import { EventContext, EventModel, EventWithContext } from "../../api/Events";
|
|
import { DEFAULT_CONFIG } from "../../api/Config";
|
|
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
|
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
|
|
import PFFlex from "@patternfly/patternfly/layouts/Flex/flex.css";
|
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
|
import PFList from "@patternfly/patternfly/components/List/list.css";
|
|
import { VERSION } from "../../constants";
|
|
|
|
@customElement("ak-event-info")
|
|
export class EventInfo extends LitElement {
|
|
|
|
@property({attribute: false})
|
|
event!: EventWithContext;
|
|
|
|
static get styles(): CSSResult[] {
|
|
return [PFBase, PFButton, PFFlex, PFList, PFDescriptionList,
|
|
css`
|
|
code {
|
|
display: block;
|
|
white-space: pre-wrap;
|
|
}
|
|
.pf-l-flex {
|
|
justify-content: space-between;
|
|
}
|
|
.pf-l-flex__item {
|
|
min-width: 25%;
|
|
}
|
|
iframe {
|
|
width: 100%;
|
|
height: 50rem;
|
|
}
|
|
`
|
|
];
|
|
}
|
|
|
|
getModelInfo(context: EventModel): TemplateResult {
|
|
if (context === null) {
|
|
return html`<span>-</span>`;
|
|
}
|
|
return html`<dl class="pf-c-description-list pf-m-horizontal">
|
|
<div class="pf-c-description-list__group">
|
|
<dt class="pf-c-description-list__term">
|
|
<span class="pf-c-description-list__text">${t`UID`}</span>
|
|
</dt>
|
|
<dd class="pf-c-description-list__description">
|
|
<div class="pf-c-description-list__text">${context.pk}</div>
|
|
</dd>
|
|
</div>
|
|
<div class="pf-c-description-list__group">
|
|
<dt class="pf-c-description-list__term">
|
|
<span class="pf-c-description-list__text">${t`Name`}</span>
|
|
</dt>
|
|
<dd class="pf-c-description-list__description">
|
|
<div class="pf-c-description-list__text">${context.name}</div>
|
|
</dd>
|
|
</div>
|
|
<div class="pf-c-description-list__group">
|
|
<dt class="pf-c-description-list__term">
|
|
<span class="pf-c-description-list__text">${t`App`}</span>
|
|
</dt>
|
|
<dd class="pf-c-description-list__description">
|
|
<div class="pf-c-description-list__text">${context.app}</div>
|
|
</dd>
|
|
</div>
|
|
<div class="pf-c-description-list__group">
|
|
<dt class="pf-c-description-list__term">
|
|
<span class="pf-c-description-list__text">${t`Model Name`}</span>
|
|
</dt>
|
|
<dd class="pf-c-description-list__description">
|
|
<div class="pf-c-description-list__text">${context.model_name}</div>
|
|
</dd>
|
|
</div>
|
|
</dl>`;
|
|
}
|
|
|
|
getEmailInfo(context: EventContext): TemplateResult {
|
|
if (context === null) {
|
|
return html`<span>-</span>`;
|
|
}
|
|
return html`<dl class="pf-c-description-list pf-m-horizontal">
|
|
<div class="pf-c-description-list__group">
|
|
<dt class="pf-c-description-list__term">
|
|
<span class="pf-c-description-list__text">${t`Message`}</span>
|
|
</dt>
|
|
<dd class="pf-c-description-list__description">
|
|
<div class="pf-c-description-list__text">${context.message}</div>
|
|
</dd>
|
|
</div>
|
|
<div class="pf-c-description-list__group">
|
|
<dt class="pf-c-description-list__term">
|
|
<span class="pf-c-description-list__text">${t`Subject`}</span>
|
|
</dt>
|
|
<dd class="pf-c-description-list__description">
|
|
<div class="pf-c-description-list__text">${context.subject}</div>
|
|
</dd>
|
|
</div>
|
|
<div class="pf-c-description-list__group">
|
|
<dt class="pf-c-description-list__term">
|
|
<span class="pf-c-description-list__text">${t`From`}</span>
|
|
</dt>
|
|
<dd class="pf-c-description-list__description">
|
|
<div class="pf-c-description-list__text">${context.from_email}</div>
|
|
</dd>
|
|
</div>
|
|
<div class="pf-c-description-list__group">
|
|
<dt class="pf-c-description-list__term">
|
|
<span class="pf-c-description-list__text">${t`To`}</span>
|
|
</dt>
|
|
<dd class="pf-c-description-list__description">
|
|
<div class="pf-c-description-list__text">
|
|
${(context.to_email as string[]).map(to => {
|
|
return html`<li>${to}</li>`;
|
|
})}
|
|
</div>
|
|
</dd>
|
|
</div>
|
|
</dl>`;
|
|
}
|
|
|
|
defaultResponse(): TemplateResult {
|
|
return html`<div class="pf-l-flex">
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`Context`}</h3>
|
|
<code>${JSON.stringify(this.event?.context, null, 4)}</code>
|
|
</div>
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`User`}</h3>
|
|
<code>${JSON.stringify(this.event?.user, null, 4)}</code>
|
|
</div>
|
|
</div>`;
|
|
}
|
|
|
|
buildGitHubIssueUrl(context: EventContext): string {
|
|
const httpRequest = this.event.context.http_request as EventContext;
|
|
let title = "";
|
|
if (httpRequest) {
|
|
title = `${httpRequest?.method} ${httpRequest?.path}`;
|
|
}
|
|
// https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-issues/about-automation-for-issues-and-pull-requests-with-query-parameters
|
|
const fullBody = `
|
|
**Describe the bug**
|
|
A clear and concise description of what the bug is.
|
|
|
|
**To Reproduce**
|
|
Steps to reproduce the behavior:
|
|
1. Go to '...'
|
|
2. Click on '....'
|
|
3. Scroll down to '....'
|
|
4. See error
|
|
|
|
**Expected behavior**
|
|
A clear and concise description of what you expected to happen.
|
|
|
|
**Screenshots**
|
|
If applicable, add screenshots to help explain your problem.
|
|
|
|
**Logs**
|
|
<details>
|
|
<summary>Stacktrace from authentik</summary>
|
|
|
|
\`\`\`
|
|
${context.message as string}
|
|
\`\`\`
|
|
</details>
|
|
|
|
|
|
**Version and Deployment (please complete the following information):**
|
|
- authentik version: ${VERSION}
|
|
- Deployment: [e.g. docker-compose, helm]
|
|
|
|
**Additional context**
|
|
Add any other context about the problem here.
|
|
`;
|
|
return `https://github.com/goauthentik/authentik/issues/
|
|
new?labels=bug+from_authentik&title=${encodeURIComponent(title)}
|
|
&body=${encodeURIComponent(fullBody)}`.trim();
|
|
}
|
|
|
|
render(): TemplateResult {
|
|
if (!this.event) {
|
|
return html`<ak-spinner size=${PFSize.Medium}></ak-spinner>`;
|
|
}
|
|
switch (this.event?.action) {
|
|
case EventMatcherPolicyActionEnum.ModelCreated:
|
|
case EventMatcherPolicyActionEnum.ModelUpdated:
|
|
case EventMatcherPolicyActionEnum.ModelDeleted:
|
|
return html`
|
|
<h3>${t`Affected model:`}</h3>
|
|
${this.getModelInfo(this.event.context?.model as EventModel)}
|
|
`;
|
|
case EventMatcherPolicyActionEnum.AuthorizeApplication:
|
|
return html`<div class="pf-l-flex">
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`Authorized application:`}</h3>
|
|
${this.getModelInfo(this.event.context.authorized_application as EventModel)}
|
|
</div>
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`Using flow`}</h3>
|
|
<span>${until(new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({
|
|
flowUuid: this.event.context.flow as string,
|
|
}).then(resp => {
|
|
return html`<a href="#/flow/flows/${resp.results[0].slug}">${resp.results[0].name}</a>`;
|
|
}), html`<ak-spinner size=${PFSize.Medium}></ak-spinner>`)}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<ak-expand>${this.defaultResponse()}</ak-expand>`;
|
|
case EventMatcherPolicyActionEnum.EmailSent:
|
|
return html`<h3>${t`Email info:`}</h3>
|
|
${this.getEmailInfo(this.event.context)}
|
|
<ak-expand>
|
|
<iframe srcdoc=${this.event.context.body}></iframe>
|
|
</ak-expand>`;
|
|
case EventMatcherPolicyActionEnum.SecretView:
|
|
return html`
|
|
<h3>${t`Secret:`}</h3>
|
|
${this.getModelInfo(this.event.context.secret as EventModel)}`;
|
|
case EventMatcherPolicyActionEnum.SystemException:
|
|
return html`
|
|
<a
|
|
class="pf-c-button pf-m-primary"
|
|
target="_blank"
|
|
href=${this.buildGitHubIssueUrl(
|
|
this.event.context
|
|
)}>
|
|
${t`Open issue on GitHub...`}
|
|
</a>
|
|
<div class="pf-l-flex">
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`Exception`}</h3>
|
|
<code>${this.event.context.message}</code>
|
|
</div>
|
|
</div>
|
|
<ak-expand>${this.defaultResponse()}</ak-expand>`;
|
|
case EventMatcherPolicyActionEnum.PropertyMappingException:
|
|
return html`<div class="pf-l-flex">
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`Exception`}</h3>
|
|
<code>${this.event.context.message || this.event.context.error}</code>
|
|
</div>
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`Expression`}</h3>
|
|
<code>${this.event.context.expression}</code>
|
|
</div>
|
|
</div>
|
|
<ak-expand>${this.defaultResponse()}</ak-expand>`;
|
|
case EventMatcherPolicyActionEnum.PolicyException:
|
|
return html`<div class="pf-l-flex">
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`Binding`}</h3>
|
|
${this.getModelInfo(this.event.context.binding as EventModel)}
|
|
</div>
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`Request`}</h3>
|
|
<ul class="pf-c-list">
|
|
<li>${t`Object`}: ${this.getModelInfo((this.event.context.request as EventContext).obj as EventModel)}</li>
|
|
<li><span>${t`Context`}: <code>${JSON.stringify((this.event.context.request as EventContext).context, null, 4)}</code></span></li>
|
|
</ul>
|
|
</div>
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`Exception`}</h3>
|
|
<code>${this.event.context.message || this.event.context.error}</code>
|
|
</div>
|
|
</div>
|
|
<ak-expand>${this.defaultResponse()}</ak-expand>`;
|
|
case EventMatcherPolicyActionEnum.PolicyExecution:
|
|
return html`<div class="pf-l-flex">
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`Binding`}</h3>
|
|
${this.getModelInfo(this.event.context.binding as EventModel)}
|
|
</div>
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`Request`}</h3>
|
|
<ul class="pf-c-list">
|
|
<li>${t`Object`}: ${this.getModelInfo((this.event.context.request as EventContext).obj as EventModel)}</li>
|
|
<li><span>${t`Context`}: <code>${JSON.stringify((this.event.context.request as EventContext).context, null, 4)}</code></span></li>
|
|
</ul>
|
|
</div>
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`Result`}</h3>
|
|
<ul class="pf-c-list">
|
|
<li>${t`Passing`}: ${(this.event.context.result as EventContext).passing}</li>
|
|
<li>${t`Messages`}:
|
|
<ul class="pf-c-list">
|
|
${((this.event.context.result as EventContext).messages as string[]).map(msg => {
|
|
return html`<li>${msg}</li>`;
|
|
})}
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<ak-expand>${this.defaultResponse()}</ak-expand>`;
|
|
case EventMatcherPolicyActionEnum.ConfigurationError:
|
|
return html`<h3>${this.event.context.message}</h3>
|
|
<ak-expand>${this.defaultResponse()}</ak-expand>`;
|
|
case EventMatcherPolicyActionEnum.UpdateAvailable:
|
|
return html`<h3>${t`New version available!`}</h3>
|
|
<a
|
|
target="_blank"
|
|
href="https://github.com/goauthentik/authentik/releases/tag/version%2F${this.event.context.new_version}">
|
|
${this.event.context.new_version}
|
|
</a>`;
|
|
// Action types which typically don't record any extra context.
|
|
// If context is not empty, we fall to the default response.
|
|
case EventMatcherPolicyActionEnum.Login:
|
|
if ("using_source" in this.event.context) {
|
|
return html`<div class="pf-l-flex">
|
|
<div class="pf-l-flex__item">
|
|
<h3>${t`Using source`}</h3>
|
|
${this.getModelInfo(this.event.context.using_source as EventModel)}
|
|
</div>
|
|
</div>`;
|
|
}
|
|
return this.defaultResponse();
|
|
case EventMatcherPolicyActionEnum.LoginFailed:
|
|
return html`
|
|
<h3>${t`Attempted to log in as ${this.event.context.username}`}</h3>
|
|
<ak-expand>${this.defaultResponse()}</ak-expand>`;
|
|
case EventMatcherPolicyActionEnum.Logout:
|
|
if (this.event.context === {}) {
|
|
return html`<span>${t`No additional data available.`}</span>`;
|
|
}
|
|
return this.defaultResponse();
|
|
default:
|
|
return this.defaultResponse();
|
|
}
|
|
}
|
|
|
|
}
|