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