Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion e2e-tests/playwright/lib/src/server/default_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,7 @@
EnableAIRecaps: false,
ClassificationMarkings: true,
IntegratedBoards: false,
CJKSearch: false,
CJKSearch: true,
ManagedChannelCategories: false,
MobileEphemeralMode: true,
},
Expand All @@ -810,7 +810,7 @@
MoveThreadFromGroupMessageChannelEnable: false,
},
ConnectedWorkspacesSettings: {
EnableSharedChannels: false,

Check warning on line 813 in e2e-tests/playwright/lib/src/server/default_config.ts

View workflow job for this annotation

GitHub Actions / check

File has too many lines (868). Maximum allowed is 800
EnableRemoteClusterService: false,
DisableSharedChannelsStatusSync: false,
SyncUsersOnConnectionOpen: false,
Expand Down
41 changes: 41 additions & 0 deletions server/channels/api4/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10693,6 +10693,47 @@ func TestGetSessionAttributesManifest(t *testing.T) {
CheckOKStatus(t, resp)
require.Empty(t, manifest)
})

t.Run("enabled field carries its seeded display name", func(t *testing.T) {
const desktopUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Mattermost/3.7.1 Chrome/56.0.2924.87 Electron/1.6.11 Safari/537.36"

group, appErr := th.App.GetPropertyGroup(th.Context, model.SessionAttributesPropertyGroupName)
require.Nil(t, appErr)
fields, appErr := th.App.SearchPropertyFields(th.Context, group.ID, model.PropertyFieldSearchOpts{PerPage: 100})
require.Nil(t, appErr)

var hardwareField *model.PropertyField
for _, field := range fields {
if field.Name == model.SessionAttributesPropertyFieldHardwareID {
hardwareField = field
break
}
}
require.NotNil(t, hardwareField)
if hardwareField.Attrs == nil {
hardwareField.Attrs = model.StringInterface{}
}
hardwareField.Attrs["enabled"] = true
_, _, appErr = th.App.UpdatePropertyFields(th.Context, group.ID, []*model.PropertyField{hardwareField}, true, "")
require.Nil(t, appErr)

th.Client.HTTPHeader = map[string]string{"User-Agent": desktopUserAgent}
defer func() { th.Client.HTTPHeader = nil }()

manifest, resp, err := th.Client.GetSessionAttributesManifest(context.Background())
require.NoError(t, err)
CheckOKStatus(t, resp)

var hardwareEntry *model.SessionAttributeManifestEntry
for _, entry := range manifest {
if entry.Name == model.SessionAttributesPropertyFieldHardwareID {
hardwareEntry = entry
break
}
}
require.NotNil(t, hardwareEntry)
require.Equal(t, model.SessionAttributesDisplayNameHardwareID, hardwareEntry.DisplayName)
})
}

// setSessionAttributeDeviceID configures the test client to send a desktop
Expand Down
1 change: 1 addition & 0 deletions server/channels/app/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,7 @@ func (s *Server) seedSessionAttributeFields(groupID string) error {
if current, ok := existingByName[expected.Name]; ok {
current.Type = expected.Type
current.Attrs["platforms"] = expected.Attrs["platforms"]
current.Attrs[model.SAAttrDisplayName] = expected.Attrs[model.SAAttrDisplayName]
current.ObjectType = expected.ObjectType
current.TargetType = expected.TargetType
current.Protected = expected.Protected
Expand Down
2 changes: 2 additions & 0 deletions server/channels/app/migrations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ func TestDoSetupSessionAttributesProperties(t *testing.T) {
require.NotNil(t, field.PermissionValues)
require.Equal(t, model.PermissionLevelSysadmin, *field.PermissionValues, "field %q permission_values", field.Name)
require.Equal(t, false, field.Attrs["enabled"], "field %q must seed disabled", field.Name)
require.NotEmpty(t, field.Attrs[model.SAAttrDisplayName], "field %q must seed a display name", field.Name)
}

ipField := fieldsByName[model.SessionAttributesPropertyFieldIPAddress]
Expand All @@ -401,6 +402,7 @@ func TestDoSetupSessionAttributesProperties(t *testing.T) {
// The typed attrs must survive the DB round trip so the app reads back what it seeded.
saField, err := model.SAFieldFromPropertyField(networkField)
require.NoError(t, err)
require.Equal(t, model.SessionAttributesDisplayNameNetworkInterfaceType, saField.Attrs.DisplayName)
require.Equal(t, model.SessionAttributeDefaultTTLNetworkIdentity, saField.Attrs.TTLSeconds)
require.Equal(t, model.SessionAttributeDefaultGraceNetworkIdentity, saField.Attrs.GracePeriodSeconds)
require.ElementsMatch(t,
Expand Down
2 changes: 1 addition & 1 deletion server/public/model/feature_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func (f *FeatureFlags) SetDefaults() {

f.IntegratedBoards = false

f.CJKSearch = false
f.CJKSearch = true

f.AggregatePluginMetrics = false

Expand Down
67 changes: 45 additions & 22 deletions server/public/model/session_attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,28 @@ const (
SessionAttributesPropertyFieldIPAddress = "ip_address"
)

const (
SessionAttributesDisplayNameClientIPAddress = "Client IP address"
SessionAttributesDisplayNameNetworkInterfaceType = "Network interface type"
SessionAttributesDisplayNameVPNActive = "VPN active"
SessionAttributesDisplayNameSSID = "SSID"
SessionAttributesDisplayNameTLSDDeviceID = "TLS device ID"
SessionAttributesDisplayNameClientDeviceID = "Device ID"
SessionAttributesDisplayNameMDMEnrolled = "MDM enrolled"
SessionAttributesDisplayNameHardwareID = "Hardware ID"
SessionAttributesDisplayNameOSPlatform = "OS platform"
SessionAttributesDisplayNameOSVersion = "OS version"
SessionAttributesDisplayNameClientVersion = "Client version"
SessionAttributesDisplayNameJailbreakDetected = "Jailbreak detected"
SessionAttributesDisplayNameServerFQDN = "Server FQDN"
SessionAttributesDisplayNameClientFQDN = "Client FQDN"
SessionAttributesDisplayNameUserAgentPlatform = "User agent platform"
SessionAttributesDisplayNameUserAgentOS = "User agent OS"
SessionAttributesDisplayNameUserAgentBrowserName = "User agent browser name"
SessionAttributesDisplayNameUserAgentBrowserVersion = "User agent browser version"
SessionAttributesDisplayNameIPAddress = "IP address"
)

const (
SAAttrEnabled = "enabled"
SAAttrPlatforms = "platforms"
Expand Down Expand Up @@ -184,8 +206,9 @@ func sessionAttributeFieldAttrs(platforms []string, ttl, grace int) StringInterf
}
}

func sessionAttributeField(groupID, name string, fieldType PropertyFieldType, platforms []string, ttl, grace int, extraAttrs StringInterface) *PropertyField {
func sessionAttributeField(groupID, name, displayName string, fieldType PropertyFieldType, platforms []string, ttl, grace int, extraAttrs StringInterface) *PropertyField {
attrs := sessionAttributeFieldAttrs(platforms, ttl, grace)
attrs[SAAttrDisplayName] = displayName
maps.Copy(attrs, extraAttrs)
return &PropertyField{
GroupID: groupID,
Expand Down Expand Up @@ -217,9 +240,9 @@ func SessionAttributeSystemFields(groupID string) []*PropertyField {
}

return []*PropertyField{
sessionAttributeField(groupID, SessionAttributesPropertyFieldIPAddress, PropertyFieldTypeText, allPlatforms, SessionAttributeDefaultTTLNetworkIdentity, SessionAttributeDefaultGraceNetworkIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldClientIPAddress, PropertyFieldTypeText, clientsOnly, SessionAttributeDefaultTTLNetworkIdentity, SessionAttributeDefaultGraceNetworkIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldNetworkInterfaceType, PropertyFieldTypeSelect, clientsOnly, SessionAttributeDefaultTTLNetworkIdentity, SessionAttributeDefaultGraceNetworkIdentity, StringInterface{
sessionAttributeField(groupID, SessionAttributesPropertyFieldIPAddress, SessionAttributesDisplayNameIPAddress, PropertyFieldTypeText, allPlatforms, SessionAttributeDefaultTTLNetworkIdentity, SessionAttributeDefaultGraceNetworkIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldClientIPAddress, SessionAttributesDisplayNameClientIPAddress, PropertyFieldTypeText, clientsOnly, SessionAttributeDefaultTTLNetworkIdentity, SessionAttributeDefaultGraceNetworkIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldNetworkInterfaceType, SessionAttributesDisplayNameNetworkInterfaceType, PropertyFieldTypeSelect, clientsOnly, SessionAttributeDefaultTTLNetworkIdentity, SessionAttributeDefaultGraceNetworkIdentity, StringInterface{
PropertyFieldAttributeOptions: []map[string]string{
{"name": "wifi"},
{"name": "ethernet"},
Expand All @@ -229,23 +252,23 @@ func SessionAttributeSystemFields(groupID string) []*PropertyField {
{"name": "other"},
},
}),
sessionAttributeField(groupID, SessionAttributesPropertyFieldVPNActive, PropertyFieldTypeSelect, clientsOnly, SessionAttributeDefaultTTLNetworkIdentity, SessionAttributeDefaultGraceNetworkIdentity, boolSelectOptions),
sessionAttributeField(groupID, SessionAttributesPropertyFieldSSID, PropertyFieldTypeText, clientsOnly, SessionAttributeDefaultTTLNetworkIdentity, SessionAttributeDefaultGraceNetworkIdentity, nil),

sessionAttributeField(groupID, SessionAttributesPropertyFieldMDMEnrolled, PropertyFieldTypeSelect, clientsOnly, SessionAttributeDefaultTTLPosture, SessionAttributeDefaultGracePosture, boolSelectOptions),
sessionAttributeField(groupID, SessionAttributesPropertyFieldJailbreakDetected, PropertyFieldTypeSelect, mobileOnly, SessionAttributeDefaultTTLPosture, SessionAttributeDefaultGracePosture, boolSelectOptions),
sessionAttributeField(groupID, SessionAttributesPropertyFieldOSPlatform, PropertyFieldTypeText, clientsOnly, SessionAttributeDefaultTTLPosture, SessionAttributeDefaultGracePosture, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldOSVersion, PropertyFieldTypeText, clientsOnly, SessionAttributeDefaultTTLPosture, SessionAttributeDefaultGracePosture, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldClientVersion, PropertyFieldTypeText, clientsOnly, SessionAttributeDefaultTTLPosture, SessionAttributeDefaultGracePosture, nil),

sessionAttributeField(groupID, SessionAttributesPropertyFieldUserAgentPlatform, PropertyFieldTypeText, allPlatforms, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldUserAgentOS, PropertyFieldTypeText, allPlatforms, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldUserAgentBrowserName, PropertyFieldTypeText, allPlatforms, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldUserAgentBrowserVersion, PropertyFieldTypeText, allPlatforms, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldTLSDDeviceID, PropertyFieldTypeText, desktopBrowser, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldClientDeviceID, PropertyFieldTypeText, mobileOnly, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldHardwareID, PropertyFieldTypeText, desktopOnly, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldServerFQDN, PropertyFieldTypeText, clientsOnly, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldClientFQDN, PropertyFieldTypeText, desktopOnly, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldVPNActive, SessionAttributesDisplayNameVPNActive, PropertyFieldTypeSelect, clientsOnly, SessionAttributeDefaultTTLNetworkIdentity, SessionAttributeDefaultGraceNetworkIdentity, boolSelectOptions),
sessionAttributeField(groupID, SessionAttributesPropertyFieldSSID, SessionAttributesDisplayNameSSID, PropertyFieldTypeText, clientsOnly, SessionAttributeDefaultTTLNetworkIdentity, SessionAttributeDefaultGraceNetworkIdentity, nil),

sessionAttributeField(groupID, SessionAttributesPropertyFieldMDMEnrolled, SessionAttributesDisplayNameMDMEnrolled, PropertyFieldTypeSelect, clientsOnly, SessionAttributeDefaultTTLPosture, SessionAttributeDefaultGracePosture, boolSelectOptions),
sessionAttributeField(groupID, SessionAttributesPropertyFieldJailbreakDetected, SessionAttributesDisplayNameJailbreakDetected, PropertyFieldTypeSelect, mobileOnly, SessionAttributeDefaultTTLPosture, SessionAttributeDefaultGracePosture, boolSelectOptions),
sessionAttributeField(groupID, SessionAttributesPropertyFieldOSPlatform, SessionAttributesDisplayNameOSPlatform, PropertyFieldTypeText, clientsOnly, SessionAttributeDefaultTTLPosture, SessionAttributeDefaultGracePosture, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldOSVersion, SessionAttributesDisplayNameOSVersion, PropertyFieldTypeText, clientsOnly, SessionAttributeDefaultTTLPosture, SessionAttributeDefaultGracePosture, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldClientVersion, SessionAttributesDisplayNameClientVersion, PropertyFieldTypeText, clientsOnly, SessionAttributeDefaultTTLPosture, SessionAttributeDefaultGracePosture, nil),

sessionAttributeField(groupID, SessionAttributesPropertyFieldUserAgentPlatform, SessionAttributesDisplayNameUserAgentPlatform, PropertyFieldTypeText, allPlatforms, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldUserAgentOS, SessionAttributesDisplayNameUserAgentOS, PropertyFieldTypeText, allPlatforms, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldUserAgentBrowserName, SessionAttributesDisplayNameUserAgentBrowserName, PropertyFieldTypeText, allPlatforms, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldUserAgentBrowserVersion, SessionAttributesDisplayNameUserAgentBrowserVersion, PropertyFieldTypeText, allPlatforms, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldTLSDDeviceID, SessionAttributesDisplayNameTLSDDeviceID, PropertyFieldTypeText, desktopBrowser, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldClientDeviceID, SessionAttributesDisplayNameClientDeviceID, PropertyFieldTypeText, mobileOnly, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldHardwareID, SessionAttributesDisplayNameHardwareID, PropertyFieldTypeText, desktopOnly, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldServerFQDN, SessionAttributesDisplayNameServerFQDN, PropertyFieldTypeText, clientsOnly, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
sessionAttributeField(groupID, SessionAttributesPropertyFieldClientFQDN, SessionAttributesDisplayNameClientFQDN, PropertyFieldTypeText, desktopOnly, SessionAttributeDefaultTTLIdentity, SessionAttributeDefaultGraceIdentity, nil),
}
}
30 changes: 30 additions & 0 deletions server/public/model/session_attributes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,36 @@ func TestSAFieldFromPropertyField(t *testing.T) {
assert.Equal(t, "VPN Active", saField.Attrs.DisplayName)
}

func TestSessionAttributeSystemFieldsDisplayNames(t *testing.T) {
fields := SessionAttributeSystemFields("group-id")
require.NotEmpty(t, fields)

displayNamesByName := make(map[string]string, len(fields))
for _, field := range fields {
saField, err := SAFieldFromPropertyField(field)
require.NoError(t, err)
require.NotEmpty(t, saField.Attrs.DisplayName, "field %q must have a display name", field.Name)
displayNamesByName[field.Name] = saField.Attrs.DisplayName
}

expected := map[string]string{
SessionAttributesPropertyFieldClientIPAddress: SessionAttributesDisplayNameClientIPAddress,
SessionAttributesPropertyFieldNetworkInterfaceType: SessionAttributesDisplayNameNetworkInterfaceType,
SessionAttributesPropertyFieldVPNActive: SessionAttributesDisplayNameVPNActive,
SessionAttributesPropertyFieldSSID: SessionAttributesDisplayNameSSID,
SessionAttributesPropertyFieldClientDeviceID: SessionAttributesDisplayNameClientDeviceID,
SessionAttributesPropertyFieldHardwareID: SessionAttributesDisplayNameHardwareID,
SessionAttributesPropertyFieldMDMEnrolled: SessionAttributesDisplayNameMDMEnrolled,
SessionAttributesPropertyFieldClientVersion: SessionAttributesDisplayNameClientVersion,
SessionAttributesPropertyFieldOSPlatform: SessionAttributesDisplayNameOSPlatform,
SessionAttributesPropertyFieldOSVersion: SessionAttributesDisplayNameOSVersion,
SessionAttributesPropertyFieldJailbreakDetected: SessionAttributesDisplayNameJailbreakDetected,
}
for name, displayName := range expected {
assert.Equal(t, displayName, displayNamesByName[name], "display name for %q", name)
}
}

func TestSAFieldEnabledForPlatform(t *testing.T) {
field := &PropertyField{
Name: SessionAttributesPropertyFieldVPNActive,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,6 @@ jest.mock('./list_item_size_observer', () => {
};
});

jest.mock('lodash/debounce', () => {
return jest.fn((fn) => {
const debouncedFn = (...args: any[]) => fn(...args);
debouncedFn.cancel = jest.fn();
debouncedFn.flush = jest.fn();
return debouncedFn;
});
});

import ListItem from './list_item';

describe('ListItem', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import debounce from 'lodash/debounce';
import type {ReactNode} from 'react';
import React, {memo, useLayoutEffect, useRef} from 'react';

import {ListItemSizeObserver} from './list_item_size_observer';

const RESIZE_DEBOUNCE_TIME = 200; // in ms

const listItemSizeObserver = ListItemSizeObserver.getInstance();

export interface Props {
Expand Down Expand Up @@ -47,31 +44,21 @@ const ListItem = (props: Props) => {
props.onHeightChange(props.itemId, newHeight, false);
}, [props.itemId]);

// This effects adds the observer which calls height change callback debounced
// This effects adds the observer which calls height change callback
useLayoutEffect(() => {
const debouncedOnHeightChange = debounce((changedHeight: number) => {
// Check if component is still mounted as it may have been
// unmounted by the time the debounced function is called
function itemRowSizeObserverCallback(changedHeight: number) {
if (!rowRef.current) {
return;
}

if (changedHeight !== heightRef.current) {
// If width of container has changed then scroll bar position will be out of sync
// so we need to force a scroll correction
const forceScrollCorrection = rowRef.current.offsetWidth !== widthRef.current;

heightRef.current = changedHeight;

props.onHeightChange(props.itemId, changedHeight, forceScrollCorrection);
}, RESIZE_DEBOUNCE_TIME);
const forceScrollCorrection = rowRef.current.offsetWidth !== widthRef.current;

function itemRowSizeObserverCallback(changedHeight: number) {
if (!rowRef.current) {
return;
}
heightRef.current = changedHeight;

if (changedHeight !== heightRef.current) {
debouncedOnHeightChange(changedHeight);
props.onHeightChange(props.itemId, changedHeight, forceScrollCorrection);
}
}

Expand All @@ -85,7 +72,6 @@ const ListItem = (props: Props) => {
return () => {
// We remove the observer here from a row
cleanupSizeObserver?.();
debouncedOnHeightChange?.cancel();
props.onUnmount(props.itemId, indexRef.current);
};
}, [props.itemId]);
Expand Down
Loading