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`-`;
}
return html`
-
${t`Name`}
-
${context.name}
-
${t`Model Name`}
-
${context.model_name}
`;
}
getEmailInfo(context: EventContext): TemplateResult {
if (context === null) {
return html`-`;
}
return html`
-
${t`Message`}
-
${context.message}
-
${t`Subject`}
-
${context.subject}
-
${t`From`}
-
${context.from_email}
-
${t`To`}
-
${(context.to_email as string[]).map(to => {
return html`
- ${to}
`;
})}
`;
}
defaultResponse(): TemplateResult {
return html`
${t`Context`}
${JSON.stringify(this.event?.context, null, 4)}
${t`User`}
${JSON.stringify(this.event?.user, null, 4)}
`;
}
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**
Stacktrace from authentik
\`\`\`
${context.message as string}
\`\`\`
**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``;
}
switch (this.event?.action) {
case EventMatcherPolicyActionEnum.ModelCreated:
case EventMatcherPolicyActionEnum.ModelUpdated:
case EventMatcherPolicyActionEnum.ModelDeleted:
return html`
${t`Affected model:`}
${this.getModelInfo(this.event.context?.model as EventModel)}
`;
case EventMatcherPolicyActionEnum.AuthorizeApplication:
return html`
${t`Authorized application:`}
${this.getModelInfo(this.event.context.authorized_application as EventModel)}
${t`Using flow`}
${until(new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({
flowUuid: this.event.context.flow as string,
}).then(resp => {
return html`${resp.results[0].name}`;
}), html``)}
${this.defaultResponse()}`;
case EventMatcherPolicyActionEnum.EmailSent:
return html`${t`Email info:`}
${this.getEmailInfo(this.event.context)}
`;
case EventMatcherPolicyActionEnum.SecretView:
return html`
${t`Secret:`}
${this.getModelInfo(this.event.context.secret as EventModel)}`;
case EventMatcherPolicyActionEnum.SystemException:
return html`
${t`Open issue on GitHub...`}
${t`Exception`}
${this.event.context.message}
${this.defaultResponse()}`;
case EventMatcherPolicyActionEnum.PropertyMappingException:
return html`
${t`Exception`}
${this.event.context.message || this.event.context.error}
${t`Expression`}
${this.event.context.expression}
${this.defaultResponse()}`;
case EventMatcherPolicyActionEnum.PolicyException:
return html`
${t`Binding`}
${this.getModelInfo(this.event.context.binding as EventModel)}
${t`Request`}
- ${t`Object`}: ${this.getModelInfo((this.event.context.request as EventContext).obj as EventModel)}
- ${t`Context`}:
${JSON.stringify((this.event.context.request as EventContext).context, null, 4)}
${t`Exception`}
${this.event.context.message || this.event.context.error}
${this.defaultResponse()}`;
case EventMatcherPolicyActionEnum.PolicyExecution:
return html`
${t`Binding`}
${this.getModelInfo(this.event.context.binding as EventModel)}
${t`Request`}
- ${t`Object`}: ${this.getModelInfo((this.event.context.request as EventContext).obj as EventModel)}
- ${t`Context`}:
${JSON.stringify((this.event.context.request as EventContext).context, null, 4)}
${t`Result`}
- ${t`Passing`}: ${(this.event.context.result as EventContext).passing}
- ${t`Messages`}:
${((this.event.context.result as EventContext).messages as string[]).map(msg => {
return html`- ${msg}
`;
})}
${this.defaultResponse()}`;
case EventMatcherPolicyActionEnum.ConfigurationError:
return html`${this.event.context.message}
${this.defaultResponse()}`;
case EventMatcherPolicyActionEnum.UpdateAvailable:
return html`${t`New version available!`}
${this.event.context.new_version}
`;
// 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`
${t`Using source`}
${this.getModelInfo(this.event.context.using_source as EventModel)}
`;
}
return this.defaultResponse();
case EventMatcherPolicyActionEnum.LoginFailed:
return html`
${t`Attempted to log in as ${this.event.context.username}`}
${this.defaultResponse()}`;
case EventMatcherPolicyActionEnum.Logout:
if (this.event.context === {}) {
return html`${t`No additional data available.`}`;
}
return this.defaultResponse();
default:
return this.defaultResponse();
}
}
}