Line data Source code
1 : /*
2 : * Copyright (C) 2021 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 :
6 15 : import cockpit from 'cockpit';
7 15 : import React, { useState } from 'react';
8 :
9 : import { Card, CardBody, CardTitle } from "@patternfly/react-core/dist/esm/components/Card/index.js";
10 : import { ListingTable } from 'cockpit-components-table.jsx';
11 :
12 : import * as timeformat from "timeformat";
13 : import { useInit } from "hooks";
14 :
15 15 : const _ = cockpit.gettext;
16 :
17 10 : export function AccountLogs({ name }) {
18 10 : const [logins, setLogins] = useState([]);
19 10 : useInit(() => {
20 10 : cockpit.spawn(["last", "--time-format", "iso", "-n25", "--fullnames", name], { environ: ["LC_ALL=C"] })
21 10 : .then(data => {
22 10 : let logins = [];
23 10 : data.split('\n').forEach(line => {
24 : // Exclude still logged in and non user lines
25 7 : if (!line.includes(name) || line.includes('still')) {
26 10 : return;
27 10 : }
28 : // Exclude tmux/screen lines
29 2 : if (line.includes('tmux') || line.includes('screen')) {
30 2 : return;
31 2 : }
32 :
33 : // format:
34 : // admin web console ::ffff:172.27.0. 2021-09-24T09:02:13+00:00 - 2021-09-24T09:04:20+00:00 (00:02)
35 6 : const lines = line.split(/ +/);
36 6 : const ended = new Date(lines[lines.length - 2]);
37 6 : const started = new Date(lines[lines.length - 4]);
38 6 : const from = lines[lines.length - 5];
39 2 : if (isNaN(started.getTime()) || isNaN(ended.getTime())) {
40 2 : return;
41 2 : }
42 :
43 6 : logins.push({
44 6 : started,
45 6 : ended,
46 6 : from
47 6 : });
48 10 : });
49 :
50 : // Only show 15 login lines
51 10 : logins = logins.slice(0, 15);
52 10 : setLogins(logins);
53 10 : })
54 0 : .catch(ex => console.error("Failed to call last:", ex)); // not-covered: OS error
55 10 : }, [name]);
56 :
57 10 : return (
58 10 : <Card isPlain id="account-logs">
59 10 : <CardTitle component="h2">{_("Login history")}</CardTitle>
60 10 : <CardBody className="contains-list">
61 10 : <ListingTable variant="compact" aria-label={ _("Login history list") }
62 10 : columns={ [
63 10 : { title: _("Started") },
64 10 : { title: _("Ended") },
65 10 : { title: _("From") },
66 10 : ] }
67 5 : rows={ logins.map((line, index) => ({
68 5 : props: { key: index },
69 5 : columns: [timeformat.dateTime(line.started), timeformat.dateTime(line.ended), line.from]
70 5 : }))} />
71 10 : </CardBody>
72 10 : </Card>
73 : );
74 10 : }
|