Skip to content

Commit

Permalink
Utility function added to check permissions on directory (#95)
Browse files Browse the repository at this point in the history
* Utility function added to check permissions on directory

* dart format fix

* Update changelog

* Using fakes for tests

* Handle null returns from `getHomeDirectory()`

* Bump version to 2.0.0 due to breaking change on default constructor
  • Loading branch information
eliasyishak authored Jun 1, 2023
1 parent a436fee commit 389925f
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 7 deletions.
3 changes: 2 additions & 1 deletion pkgs/unified_analytics/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
## 1.1.1
## 2.0.0

- Refactoring `dateStamp` utility function to be defined in `utils.dart` instead of having static methods in `Initializer` and `ConfigHandler`
- Remove the `pddFlag` now that the revisions to the PDD have been finalized to persist data in the log file and session json file
- Opting out will now delete the contents of the CLIENT ID, session json, and log files; opting back in will regenerate them as events send
- `enableAsserts` parameter added to constructors for `Analytics` to check body of POST request for Google Analytics 4 limitations
- Now checking if write permissions are enabled for user's home directory, if not allowed, `NoOpAnalytics` returned by `Analytics` factory constructor

## 1.1.0

Expand Down
18 changes: 16 additions & 2 deletions pkgs/unified_analytics/lib/src/analytics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ abstract class Analytics {
// resolve on their own
const FileSystem fs = LocalFileSystem();

// Ensure that the home directory has permissions enabled to write
final Directory? homeDirectory = getHomeDirectory(fs);
if (homeDirectory == null ||
!checkDirectoryForWritePermissions(homeDirectory)) {
return NoOpAnalytics();
}

// Resolve the OS using dart:io
final DevicePlatform platform;
if (io.Platform.operatingSystem == 'linux') {
Expand All @@ -59,7 +66,7 @@ abstract class Analytics {

return AnalyticsImpl(
tool: tool,
homeDirectory: getHomeDirectory(fs),
homeDirectory: homeDirectory,
flutterChannel: flutterChannel,
flutterVersion: flutterVersion,
dartVersion: dartVersion,
Expand Down Expand Up @@ -88,6 +95,13 @@ abstract class Analytics {
// resolve on their own
const FileSystem fs = LocalFileSystem();

// Ensure that the home directory has permissions enabled to write
final Directory? homeDirectory = getHomeDirectory(fs);
if (homeDirectory == null ||
!checkDirectoryForWritePermissions(homeDirectory)) {
return NoOpAnalytics();
}

// Resolve the OS using dart:io
final DevicePlatform platform;
if (io.Platform.operatingSystem == 'linux') {
Expand All @@ -111,7 +125,7 @@ abstract class Analytics {

return AnalyticsImpl(
tool: tool,
homeDirectory: getHomeDirectory(fs),
homeDirectory: homeDirectory,
flutterChannel: flutterChannel,
flutterVersion: flutterVersion,
dartVersion: dartVersion,
Expand Down
2 changes: 1 addition & 1 deletion pkgs/unified_analytics/lib/src/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const int kLogFileLength = 2500;
const String kLogFileName = 'dart-flutter-telemetry.log';

/// The current version of the package, should be in line with pubspec version.
const String kPackageVersion = '1.1.1';
const String kPackageVersion = '2.0.0';

/// The minimum length for a session
const int kSessionDurationMinutes = 30;
Expand Down
18 changes: 16 additions & 2 deletions pkgs/unified_analytics/lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ String get dateStamp {
return DateFormat('yyyy-MM-dd').format(clock.now());
}

/// Reads in a directory and returns `true` if write permissions are enabled
///
/// Uses the [FileStat] method `modeString()` to return a string in the form
/// of `rwxrwxrwx` where the second character in the string indicates if write
/// is enabled with a `w` or disabled with `-`
bool checkDirectoryForWritePermissions(Directory directory) {
if (!directory.existsSync()) return false;

final FileStat fileStat = directory.statSync();
return fileStat.modeString()[1] == 'w';
}

/// Format time as 'yyyy-MM-dd HH:mm:ss Z' where Z is the difference between the
/// timezone of t and UTC formatted according to RFC 822.
String formatDateTime(DateTime t) {
Expand Down Expand Up @@ -76,7 +88,7 @@ Map<String, Object?> generateRequestBody({
/// This will use environment variables to get the user's
/// home directory where all the directory will be created that will
/// contain all of the analytics files
Directory getHomeDirectory(FileSystem fs) {
Directory? getHomeDirectory(FileSystem fs) {
String? home;
Map<String, String> envVars = io.Platform.environment;

Expand All @@ -88,7 +100,9 @@ Directory getHomeDirectory(FileSystem fs) {
home = envVars['AppData'];
}

return fs.directory(home!);
if (home == null) return null;

return fs.directory(home);
}

/// Returns `true` if user has opted out of legacy analytics in Dart or Flutter
Expand Down
2 changes: 1 addition & 1 deletion pkgs/unified_analytics/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: >-
to Google Analytics.
# When updating this, keep the version consistent with the changelog and the
# value in lib/src/constants.dart.
version: 1.1.1
version: 2.0.0
repository: https://github.com/dart-lang/tools/tree/main/pkgs/unified_analytics

environment:
Expand Down
48 changes: 48 additions & 0 deletions pkgs/unified_analytics/test/no_op_analytics_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:file/file.dart';
import 'package:test/fake.dart';
import 'package:test/test.dart';

import 'package:unified_analytics/src/utils.dart';
import 'package:unified_analytics/unified_analytics.dart';

void main() {
Expand Down Expand Up @@ -45,4 +48,49 @@ void main() {

expect(analytics.logFileStats(), isNull);
});

test('Home directory without write permissions', () {
final FakeDirectory home = FakeDirectory(writeEnabled: false);

expect(checkDirectoryForWritePermissions(home), false);
});

test('Home directory with write permissions', () {
final FakeDirectory home = FakeDirectory(writeEnabled: true);

expect(checkDirectoryForWritePermissions(home), true);
});
}

class FakeDirectory extends Fake implements Directory {
final String _fakeModeString;

/// This fake directory class allows you to pass the permissions for
/// the user level, the group and global permissions will default to
/// being denied as indicated by the last 6 characters in [modeString]
FakeDirectory({
required bool writeEnabled,
bool readEnabled = true,
bool executeEnabled = true,
}) : _fakeModeString = '${readEnabled ? "r" : "-"}'
'${writeEnabled ? "w" : "-"}'
'${executeEnabled ? "x" : "-"}'
'------' {
assert(_fakeModeString.length == 9);
}

@override
bool existsSync() => true;

@override
FileStat statSync() => FakeFileStat(_fakeModeString);
}

class FakeFileStat extends Fake implements FileStat {
final String _fakeModeString;

FakeFileStat(this._fakeModeString);

@override
String modeString() => _fakeModeString;
}

0 comments on commit 389925f

Please sign in to comment.