Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add package:cedar #63

Merged
merged 1 commit into from
Mar 9, 2024
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
7 changes: 7 additions & 0 deletions packages/cedar/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/

# Avoid committing pubspec.lock for library packages; see
# https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock
3 changes: 3 additions & 0 deletions packages/cedar/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 0.1.0

- Initial version.
7 changes: 7 additions & 0 deletions packages/cedar/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# cedar

Core types and interfaces of the [Cedar](https://www.cedarpolicy.com/en) policy language in Dart.

Cedar is a policy language for defining and enforcing access control policies in a declarative way. It is used in [Celest](https://celest.dev) for ensuring that only authorized users meeting certain criteria can access your backend.

The actual implementation of the Cedar engine is in [cedar_ffi](https://pub.dev/packages/cedar_ffi), which uses FFI and Dart's native assets feature to bind to the Rust implementation of Cedar. This package only holds the Dart AST representation and is separate from `package:cedar_ffi` so that the types can be used without bundling the native assets of `package:cedar_ffi`.
1 change: 1 addition & 0 deletions packages/cedar/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include: package:lints/recommended.yaml
26 changes: 26 additions & 0 deletions packages/cedar/lib/cedar.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/// Core types and interfaces of the [Cedar](https://www.cedarpolicy.com/en)
/// policy language in Dart.
///
/// Cedar is a policy language for defining and enforcing access control
/// policies in a declarative way. It is used in [Celest](https://celest.dev)
/// for ensuring that only authorized users meeting certain criteria can access
/// your backend.
///
/// The actual implementation of the Cedar engine is in
/// [cedar_ffi](https://pub.dev/packages/cedar_ffi), which uses FFI and Dart's
/// native assets feature to bind to the Rust implementation of Cedar. This
/// package only holds the Dart AST representation and is separate from
/// `package:cedar_ffi` so that the types can be used without bundling the
/// native assets of `package:cedar_ffi`.
library;

export 'src/ast/cedar_entity.dart';
export 'src/ast/cedar_entity_id.dart';
export 'src/ast/cedar_schema.dart';
export 'src/authorization/cedar_authorization_request.dart';
export 'src/authorization/cedar_authorization_response.dart';
export 'src/authorization/cedar_authorizer.dart';
export 'src/policy/cedar_policy.dart';
export 'src/policy/cedar_policy_set.dart';
export 'src/policy/json_expr.dart';
export 'src/serializers.dart';
54 changes: 54 additions & 0 deletions packages/cedar/lib/src/ast/cedar_entity.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import 'package:cedar/src/ast/cedar_entity_id.dart';
import 'package:cedar/src/policy/json_expr.dart';

part 'cedar_entity.g.dart';

/// Dart representation of a Cedar [entity](https://docs.cedarpolicy.com/policies/syntax-entity.html).
///
/// Conforms to the entity [JSON format](https://docs.cedarpolicy.com/auth/entities-syntax.html#entities).
abstract class CedarEntity implements Built<CedarEntity, CedarEntityBuilder> {
factory CedarEntity({
required CedarEntityId id,
List<CedarEntityId> parents = const [],
Map<String, CedarValueJson> attributes = const {},
}) {
return _$CedarEntity._(
id: id,
parents: parents.build(),
attributes: attributes.build(),
);
}

factory CedarEntity.build([
void Function(CedarEntityBuilder) updates,
]) = _$CedarEntity;

factory CedarEntity.fromJson(Map<String, Object?> json) => CedarEntity(
id: CedarEntityId.fromJson(json['uid'] as Map<String, Object?>),
parents: (json['parents'] as List<Object?>)
.map((e) => CedarEntityId.fromJson(e as Map<String, Object?>))
.toList(),
attributes: (json['attrs'] as Map<Object?, Object?>)
.cast<String, Object?>()
.map((key, value) => MapEntry(key, CedarValueJson.fromJson(value))),
);

const CedarEntity._();

CedarEntityId get id;
BuiltList<CedarEntityId> get parents;
BuiltMap<String, CedarValueJson> get attributes;

Map<String, Object?> toJson() => {
'uid': id.toJson(),
'parents': parents.map((e) => e.toJson()).toList(),
'attrs': attributes
.map((key, value) => MapEntry(key, value.toJson()))
.asMap(),
};

static Serializer<CedarEntity> get serializer => _$cedarEntitySerializer;
}
201 changes: 201 additions & 0 deletions packages/cedar/lib/src/ast/cedar_entity.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 68 additions & 0 deletions packages/cedar/lib/src/ast/cedar_entity_id.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';

part 'cedar_entity_id.g.dart';

abstract class CedarEntityId
implements Built<CedarEntityId, CedarEntityIdBuilder> {
factory CedarEntityId(String type, String id) =>
_$CedarEntityId._(type: type, id: id);

factory CedarEntityId.build([
void Function(CedarEntityIdBuilder) updates,
]) = _$CedarEntityId;

factory CedarEntityId.fromJson(Map<String, Object?> json) {
switch (json) {
case {'type': final String type, 'id': final String id} ||
{'__entity': {'type': final String type, 'id': final String id}}:
return CedarEntityId(type, id);
default:
throw FormatException('Invalid entity ID JSON: $json');
}
}

const CedarEntityId._();

String get type;
String get id;

/// Returns a normalized version of this entity ID.
///
/// Cedar prohibits whitespace in entity IDs, so this method removes all
/// whitespace from the [type] and [id].
///
/// See Cedar [RFC 9](https://github.com/cedar-policy/rfcs/blob/main/text/0009-disallow-whitespace-in-entityuid.md)
/// for more information.
CedarEntityId get normalized => CedarEntityId(
type,
String.fromCharCodes(
id.runes.expand((char) {
return switch (char) {
0 => '\\0'.codeUnits,
0x9 => '\\t'.codeUnits,
0xa => '\\n'.codeUnits,
0xd => '\\r'.codeUnits,
0x22 => '\\"'.codeUnits,
0x27 => "\\'".codeUnits,
< 0x20 ||
0x7f || // Delete
0x96 || // Non-breaking space
> 0xffff =>
'\\u{${char.toRadixString(16)}}'.codeUnits,
_ => [char],
};
}),
),
);

@override
String toString() => '$type::"$id"';

Map<String, Object?> toJson() => {
'type': type,
'id': id,
};

static Serializer<CedarEntityId> get serializer => _$cedarEntityIdSerializer;
}
Loading