fix: misc
parent
ba1ed1252c
commit
526dd8347d
|
@ -46,16 +46,13 @@ func NewSQLProvider(config *schema.Configuration, name, driverName, dataSourceNa
|
|||
sqlUpdateTOTPConfigRecordSignIn: fmt.Sprintf(queryFmtUpdateTOTPConfigRecordSignIn, tableTOTPConfigurations),
|
||||
sqlUpdateTOTPConfigRecordSignInByUsername: fmt.Sprintf(queryFmtUpdateTOTPConfigRecordSignInByUsername, tableTOTPConfigurations),
|
||||
|
||||
sqlUpsertWebauthnDevice: fmt.Sprintf(queryFmtUpsertWebauthnDevice, tableWebauthnDevices),
|
||||
sqlInsertWebauthnDevice: fmt.Sprintf(queryFmtUpsertInsertDevice, tableWebauthnDevices),
|
||||
sqlSelectWebauthnDevices: fmt.Sprintf(queryFmtSelectWebauthnDevices, tableWebauthnDevices),
|
||||
sqlSelectWebauthnDevicesByUsername: fmt.Sprintf(queryFmtSelectWebauthnDevicesByUsername, tableWebauthnDevices),
|
||||
sqlSelectWebauthnDevicesByRPIDByUsername: fmt.Sprintf(queryFmtSelectWebauthnDevicesByRPIDByUsername, tableWebauthnDevices),
|
||||
sqlSelectWebauthnDeviceByID: fmt.Sprintf(queryFmtSelectWebauthnDeviceByID, tableWebauthnDevices),
|
||||
sqlUpdateWebauthnDeviceDescriptionByUsernameAndID: fmt.Sprintf(queryFmtUpdateUpdateWebauthnDeviceDescriptionByUsernameAndID, tableWebauthnDevices),
|
||||
sqlUpdateWebauthnDevicePublicKey: fmt.Sprintf(queryFmtUpdateWebauthnDevicePublicKey, tableWebauthnDevices),
|
||||
sqlUpdateWebauthnDevicePublicKeyByUsername: fmt.Sprintf(queryFmtUpdateWebauthnDevicePublicKeyByUsername, tableWebauthnDevices),
|
||||
sqlUpdateWebauthnDeviceRecordSignIn: fmt.Sprintf(queryFmtUpdateWebauthnDeviceRecordSignIn, tableWebauthnDevices),
|
||||
sqlUpdateWebauthnDeviceRecordSignInByUsername: fmt.Sprintf(queryFmtUpdateWebauthnDeviceRecordSignInByUsername, tableWebauthnDevices),
|
||||
sqlDeleteWebauthnDevice: fmt.Sprintf(queryFmtDeleteWebauthnDevice, tableWebauthnDevices),
|
||||
sqlDeleteWebauthnDeviceByUsername: fmt.Sprintf(queryFmtDeleteWebauthnDeviceByUsername, tableWebauthnDevices),
|
||||
sqlDeleteWebauthnDeviceByUsernameAndDescription: fmt.Sprintf(queryFmtDeleteWebauthnDeviceByUsernameAndDescription, tableWebauthnDevices),
|
||||
|
@ -164,17 +161,14 @@ type SQLProvider struct {
|
|||
sqlUpdateTOTPConfigRecordSignInByUsername string
|
||||
|
||||
// Table: webauthn_devices.
|
||||
sqlUpsertWebauthnDevice string
|
||||
sqlInsertWebauthnDevice string
|
||||
sqlSelectWebauthnDevices string
|
||||
sqlSelectWebauthnDevicesByUsername string
|
||||
sqlSelectWebauthnDevicesByRPIDByUsername string
|
||||
sqlSelectWebauthnDeviceByID string
|
||||
|
||||
sqlUpdateWebauthnDeviceDescriptionByUsernameAndID string
|
||||
sqlUpdateWebauthnDevicePublicKey string
|
||||
sqlUpdateWebauthnDevicePublicKeyByUsername string
|
||||
sqlUpdateWebauthnDeviceRecordSignIn string
|
||||
sqlUpdateWebauthnDeviceRecordSignInByUsername string
|
||||
|
||||
sqlDeleteWebauthnDevice string
|
||||
sqlDeleteWebauthnDeviceByUsername string
|
||||
|
@ -847,7 +841,7 @@ func (p *SQLProvider) SaveWebauthnDevice(ctx context.Context, device model.Webau
|
|||
return fmt.Errorf("error encrypting the Webauthn device public key for user '%s' kid '%x': %w", device.Username, device.KID, err)
|
||||
}
|
||||
|
||||
if _, err = p.db.ExecContext(ctx, p.sqlUpsertWebauthnDevice,
|
||||
if _, err = p.db.ExecContext(ctx, p.sqlInsertWebauthnDevice,
|
||||
device.CreatedAt, device.LastUsedAt,
|
||||
device.RPID, device.Username, device.Description,
|
||||
device.KID, device.PublicKey,
|
||||
|
|
|
@ -31,7 +31,6 @@ func NewPostgreSQLProvider(config *schema.Configuration, caCertPool *x509.CertPo
|
|||
|
||||
// Specific alterations to this provider.
|
||||
// PostgreSQL doesn't have a UPSERT statement but has an ON CONFLICT operation instead.
|
||||
provider.sqlUpsertWebauthnDevice = fmt.Sprintf(queryFmtUpsertWebauthnDevicePostgreSQL, tableWebauthnDevices)
|
||||
provider.sqlUpsertDuoDevice = fmt.Sprintf(queryFmtUpsertDuoDevicePostgreSQL, tableDuoDevices)
|
||||
provider.sqlUpsertTOTPConfig = fmt.Sprintf(queryFmtUpsertTOTPConfigurationPostgreSQL, tableTOTPConfigurations)
|
||||
provider.sqlUpsertPreferred2FAMethod = fmt.Sprintf(queryFmtUpsertPreferred2FAMethodPostgreSQL, tableUserPreferences)
|
||||
|
@ -59,14 +58,13 @@ func NewPostgreSQLProvider(config *schema.Configuration, caCertPool *x509.CertPo
|
|||
provider.sqlDeleteTOTPConfig = provider.db.Rebind(provider.sqlDeleteTOTPConfig)
|
||||
provider.sqlSelectTOTPConfigs = provider.db.Rebind(provider.sqlSelectTOTPConfigs)
|
||||
|
||||
provider.sqlInsertWebauthnDevice = provider.db.Rebind(provider.sqlInsertWebauthnDevice)
|
||||
provider.sqlSelectWebauthnDevices = provider.db.Rebind(provider.sqlSelectWebauthnDevices)
|
||||
provider.sqlSelectWebauthnDevicesByUsername = provider.db.Rebind(provider.sqlSelectWebauthnDevicesByUsername)
|
||||
provider.sqlSelectWebauthnDevicesByRPIDByUsername = provider.db.Rebind(provider.sqlSelectWebauthnDevicesByRPIDByUsername)
|
||||
provider.sqlSelectWebauthnDeviceByID = provider.db.Rebind(provider.sqlSelectWebauthnDeviceByID)
|
||||
provider.sqlUpdateWebauthnDeviceDescriptionByUsernameAndID = provider.db.Rebind(provider.sqlUpdateWebauthnDeviceDescriptionByUsernameAndID)
|
||||
provider.sqlUpdateWebauthnDevicePublicKey = provider.db.Rebind(provider.sqlUpdateWebauthnDevicePublicKey)
|
||||
provider.sqlUpdateWebauthnDevicePublicKeyByUsername = provider.db.Rebind(provider.sqlUpdateWebauthnDevicePublicKeyByUsername)
|
||||
provider.sqlUpdateWebauthnDeviceRecordSignIn = provider.db.Rebind(provider.sqlUpdateWebauthnDeviceRecordSignIn)
|
||||
provider.sqlUpdateWebauthnDeviceRecordSignInByUsername = provider.db.Rebind(provider.sqlUpdateWebauthnDeviceRecordSignInByUsername)
|
||||
provider.sqlDeleteWebauthnDevice = provider.db.Rebind(provider.sqlDeleteWebauthnDevice)
|
||||
provider.sqlDeleteWebauthnDeviceByUsername = provider.db.Rebind(provider.sqlDeleteWebauthnDeviceByUsername)
|
||||
provider.sqlDeleteWebauthnDeviceByUsernameAndDescription = provider.db.Rebind(provider.sqlDeleteWebauthnDeviceByUsernameAndDescription)
|
||||
|
|
|
@ -149,11 +149,6 @@ const (
|
|||
SET public_key = ?
|
||||
WHERE id = ?;`
|
||||
|
||||
queryFmtUpdateWebauthnDevicePublicKeyByUsername = `
|
||||
UPDATE %s
|
||||
SET public_key = ?
|
||||
WHERE username = ? AND kid = ?;`
|
||||
|
||||
queryFmtUpdateUpdateWebauthnDeviceDescriptionByUsernameAndID = `
|
||||
UPDATE %s
|
||||
SET description = ?
|
||||
|
@ -166,22 +161,9 @@ const (
|
|||
clone_warning = CASE clone_warning WHEN TRUE THEN TRUE ELSE ? END
|
||||
WHERE id = ?;`
|
||||
|
||||
queryFmtUpdateWebauthnDeviceRecordSignInByUsername = `
|
||||
UPDATE %s
|
||||
SET
|
||||
rpid = ?, last_used_at = ?, sign_count = ?,
|
||||
clone_warning = CASE clone_warning WHEN TRUE THEN TRUE ELSE ? END
|
||||
WHERE username = ? AND kid = ?;`
|
||||
|
||||
queryFmtUpsertWebauthnDevice = `
|
||||
REPLACE INTO %s (created_at, last_used_at, rpid, username, description, kid, public_key, attestation_type, transport, aaguid, sign_count, clone_warning)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`
|
||||
|
||||
queryFmtUpsertWebauthnDevicePostgreSQL = `
|
||||
queryFmtUpsertInsertDevice = `
|
||||
INSERT INTO %s (created_at, last_used_at, rpid, username, description, kid, public_key, attestation_type, transport, aaguid, sign_count, clone_warning)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
||||
ON CONFLICT (rpid, username, description)
|
||||
DO UPDATE SET created_at = $1, last_used_at = $2, kid = $6, public_key = $7, attestation_type = $8, transport = $9, aaguid = $10, sign_count = $11, clone_warning = $12;`
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`
|
||||
|
||||
queryFmtDeleteWebauthnDevice = `
|
||||
DELETE FROM %s
|
||||
|
|
|
@ -8,6 +8,7 @@ export async function PostWithOptionalResponse<T = undefined>(path: string, body
|
|||
if (res.status !== 200 || hasServiceError(res).errored) {
|
||||
throw new Error(`Failed POST to ${path}. Code: ${res.status}. Message: ${hasServiceError(res).message}`);
|
||||
}
|
||||
|
||||
return toData<T>(res);
|
||||
}
|
||||
|
||||
|
@ -32,3 +33,21 @@ export async function Get<T = undefined>(path: string): Promise<T> {
|
|||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
export async function GetWithOptionalData<T = undefined>(path: string): Promise<T | null> {
|
||||
const res = await axios.get<ServiceResponse<T>>(path);
|
||||
|
||||
if (res.status !== 200 || hasServiceError(res).errored) {
|
||||
throw new Error(`Failed GET from ${path}. Code: ${res.status}.`);
|
||||
}
|
||||
|
||||
const d = toData<T>(res);
|
||||
if (d === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!d) {
|
||||
throw new Error("unexpected type of response");
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { WebauthnDevice } from "@models/Webauthn";
|
||||
import { WebauthnDevicesPath } from "@services/Api";
|
||||
import { Get } from "@services/Client";
|
||||
import { GetWithOptionalData } from "@services/Client";
|
||||
|
||||
// getWebauthnDevices returns the list of webauthn devices for the authenticated user.
|
||||
export async function getWebauthnDevices(): Promise<WebauthnDevice[]> {
|
||||
return Get<WebauthnDevice[]>(WebauthnDevicesPath);
|
||||
export async function getWebauthnDevices(): Promise<WebauthnDevice[] | null> {
|
||||
return GetWithOptionalData<WebauthnDevice[] | null>(WebauthnDevicesPath);
|
||||
}
|
||||
|
|
|
@ -4,10 +4,9 @@ import { Fingerprint } from "@mui/icons-material";
|
|||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
|
||||
import { Box, Button, Paper, Stack, Tooltip, Typography } from "@mui/material";
|
||||
import { Box, Button, CircularProgress, Paper, Stack, Tooltip, Typography } from "@mui/material";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import LoadingButton from "@components/LoadingButton";
|
||||
import { useNotifications } from "@hooks/NotificationsContext";
|
||||
import { WebauthnDevice } from "@models/Webauthn";
|
||||
import { deleteDevice, updateDevice } from "@services/Webauthn";
|
||||
|
@ -169,26 +168,26 @@ export default function WebauthnDeviceItem(props: Props) {
|
|||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title={translate("Edit information for this Webauthn credential")}>
|
||||
<LoadingButton
|
||||
loading={loadingEdit}
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
startIcon={<EditIcon />}
|
||||
onClick={() => setShowDialogEdit(true)}
|
||||
startIcon={loadingEdit ? <CircularProgress color="inherit" size={20} /> : <EditIcon />}
|
||||
onClick={loadingEdit ? undefined : () => setShowDialogEdit(true)}
|
||||
>
|
||||
{translate("Edit")}
|
||||
</LoadingButton>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title={translate("Remove this Webauthn credential")}>
|
||||
<LoadingButton
|
||||
loading={loadingDelete}
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
startIcon={<DeleteIcon />}
|
||||
onClick={() => setShowDialogDelete(true)}
|
||||
color="primary"
|
||||
startIcon={
|
||||
loadingDelete ? <CircularProgress color="inherit" size={20} /> : <DeleteIcon />
|
||||
}
|
||||
onClick={loadingDelete ? undefined : () => setShowDialogDelete(true)}
|
||||
>
|
||||
{translate("Remove")}
|
||||
</LoadingButton>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
</Box>
|
||||
|
|
|
@ -64,11 +64,11 @@ const WebauthnDeviceRegisterDialog = function (props: Props) {
|
|||
setName("");
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
const handleClose = useCallback(() => {
|
||||
resetStates();
|
||||
|
||||
props.setCancelled();
|
||||
};
|
||||
}, [props]);
|
||||
|
||||
const finishAttestation = async () => {
|
||||
if (!result || !result.response) {
|
||||
|
|
|
@ -15,11 +15,11 @@ interface Props {
|
|||
export default function WebauthnDevicesStack(props: Props) {
|
||||
const { t: translate } = useTranslation("settings");
|
||||
|
||||
const [devices, setDevices] = useState<WebauthnDevice[]>([]);
|
||||
const [devices, setDevices] = useState<WebauthnDevice[] | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
(async function () {
|
||||
setDevices([]);
|
||||
setDevices(null);
|
||||
const devices = await getWebauthnDevices();
|
||||
setDevices(devices);
|
||||
})();
|
||||
|
@ -27,7 +27,7 @@ export default function WebauthnDevicesStack(props: Props) {
|
|||
|
||||
return (
|
||||
<Fragment>
|
||||
{devices.length !== 0 ? (
|
||||
{devices !== null && devices.length !== 0 ? (
|
||||
<Stack spacing={3}>
|
||||
{devices.map((x, idx) => (
|
||||
<WebauthnDeviceItem key={idx} index={idx} device={x} handleEdit={props.incrementRefreshState} />
|
||||
|
|
Loading…
Reference in New Issue