This commit is contained in:
thosakwe 2017-01-29 15:21:52 -05:00
parent a4fa416dfe
commit 315709e39a
8 changed files with 87 additions and 26 deletions

View file

@ -1,5 +1,5 @@
# security
[![version 0.0.5](https://img.shields.io/badge/pub-v0.0.5-red.svg)](https://pub.dartlang.org/packages/angel_security)
[![version 0.0.6](https://img.shields.io/badge/pub-v0.0.6-red.svg)](https://pub.dartlang.org/packages/angel_security)
[![build status](https://travis-ci.org/angel-dart/security.svg)](https://travis-ci.org/angel-dart/security)
Angel middleware designed to enhance application security by patching common Web security

View file

@ -1,20 +1,23 @@
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart';
import 'errors.dart';
import 'is_server_side.dart';
/// Adds the authed user's id to `data`.
///
/// Default [as] is `'userId'`.
///Default [idField] is `'id'`.
/// Default [ownerField] is `'userId'`.
/// Default [userKey] is `'user'`.
HookedServiceEventListener associateCurrentUser(
{String as,
{String idField,
String ownerField,
String userKey,
String errorMessage,
bool allowNullUserId: false,
getId(user),
setId(id, user)}) {
assignUserId(id, obj)}) {
return (HookedServiceEvent e) async {
var fieldName = as?.isNotEmpty == true ? as : 'userId';
var fieldName = ownerField?.isNotEmpty == true ? ownerField : 'userId';
var user = e.request?.grab(userKey ?? 'user');
if (user == null) {
@ -25,7 +28,18 @@ HookedServiceEventListener associateCurrentUser(
return;
}
_getId(user) => getId == null ? user?.id : getId(user);
_getId(user) {
if (getId != null)
return getId(user);
else if (user is Map)
return user[idField ?? 'id'];
else if (user is Extensible)
return user.properties[idField ?? 'id'];
else if (idField == null || idField == 'id')
return user.id;
else
return reflect(user).getField(new Symbol(idField ?? 'id')).reflectee;
}
var id = await _getId(user);
@ -33,15 +47,19 @@ HookedServiceEventListener associateCurrentUser(
throw new AngelHttpException.notProcessable(
message: 'Current user is missing a $fieldName field.');
_setId(id, user) {
if (setId != null)
return setId(id, user);
else if (user is Map)
user[fieldName] = id;
_assignUserId(id, obj) {
if (assignUserId != null)
return assignUserId(id, obj);
else if (obj is Map)
obj[fieldName] = id;
else if (obj is Extensible)
obj.properties[fieldName] = id;
else if (fieldName == 'userId')
obj.userId = id;
else
user.userId = id;
reflect(obj).setField(new Symbol(fieldName), id);
}
await _setId(id, e.data);
await _assignUserId(id, e.data);
};
}

View file

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:mirrors';
import 'package:crypto/crypto.dart';
import 'package:angel_framework/angel_framework.dart';
@ -19,8 +20,12 @@ HookedServiceEventListener hashPassword(
return getPassword(user);
else if (user is Map)
return user[passwordField ?? 'password'];
else
else if (user is Extensible)
return user.properties[passwordField ?? 'password'];
else if (passwordField == 'password')
return user?.password;
else
return reflect(user).getField(new Symbol(passwordField ?? 'password')).reflectee;
}
_setPassword(password, user) {
@ -28,8 +33,11 @@ HookedServiceEventListener hashPassword(
return setPassword(password, user);
else if (user is Map)
user[passwordField ?? 'password'] = password;
else if (user is Extensible)
user.properties[passwordField ?? password] = password;
else
user?.password = password;
reflect(user)
.setField(new Symbol(passwordField ?? 'password'), password);
}
if (e.data != null) {

View file

@ -1,3 +1,4 @@
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart';
import 'errors.dart';
import 'is_server_side.dart';
@ -8,12 +9,13 @@ import 'is_server_side.dart';
/// Default [userKey] is `'user'`.
HookedServiceEventListener queryWithCurrentUser(
{String as,
String idField,
String userKey,
String errorMessage,
bool allowNullUserId: false,
getId(user)}) {
return (HookedServiceEvent e) async {
var fieldName = as?.isNotEmpty == true ? as : 'userId';
var fieldName = idField?.isNotEmpty == true ? idField : 'id';
var user = e.request?.grab(userKey ?? 'user');
if (user == null) {
@ -24,15 +26,26 @@ HookedServiceEventListener queryWithCurrentUser(
return;
}
_getId(user) => getId == null ? user?.id : getId(user);
_getId(user) {
if (getId != null)
return getId(user);
else if (user is Map)
return user[fieldName];
else if (user is Extensible)
return user.properties[fieldName];
else if (fieldName == 'id')
return user.id;
else
return reflect(user).getField(new Symbol(fieldName)).reflectee;
}
var id = await _getId(user);
if (id == null && allowNullUserId != true)
throw new AngelHttpException.notProcessable(
message: 'Current user is missing a $fieldName field.');
message: 'Current user is missing a \'$fieldName\' field.');
var data = {fieldName: id};
var data = {as?.isNotEmpty == true ? as : 'userId': id};
e.params['query'] = e.params.containsKey('query')
? (e.params['query']..addAll(data))

View file

@ -1,10 +1,16 @@
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart';
import 'errors.dart';
import 'is_server_side.dart';
/// Restricts users to accessing only their own resources.
HookedServiceEventListener restrictToOwner(
{String userKey, String errorMessage, getId(user), getOwner(obj)}) {
{String idField,
String ownerField,
String userKey,
String errorMessage,
getId(user),
getOwner(obj)}) {
return (HookedServiceEvent e) async {
if (!isServerSide(e)) {
var user = e.request?.grab(userKey ?? 'user');
@ -18,9 +24,13 @@ HookedServiceEventListener restrictToOwner(
if (getId != null)
return getId(user);
else if (user is Map)
return user['id'];
else
return user[idField ?? 'id'];
else if (user is Extensible)
return user.properties[idField ?? 'id'];
else if (idField == null || idField == 'id')
return user.id;
else
return reflect(user).getField(new Symbol(idField ?? 'id')).reflectee;
}
var id = await _getId(user);
@ -38,9 +48,15 @@ HookedServiceEventListener restrictToOwner(
if (getOwner != null)
return getOwner(obj);
else if (obj is Map)
return obj['userId'];
else
return obj[ownerField ?? 'userId'];
else if (obj is Extensible)
return obj.properties[ownerField ?? 'userId'];
else if (ownerField == null || ownerField == 'userId')
return obj.userId;
else
return reflect(obj)
.getField(new Symbol(ownerField ?? 'userId'))
.reflectee;
}
var ownerId = await _getOwner(resource);

View file

@ -16,6 +16,8 @@ HookedServiceEventListener variantPermission(
return (HookedServiceEvent e) async {
var permission = await createPermission(e);
if (permission is PermissionBuilder) permission = permission.toPermission();
if (permission is! Permission)
throw new ArgumentError(
'createPermission must generate a Permission, whether synchronously or asynchronously.');

View file

@ -18,9 +18,11 @@ class Permission {
/// permission, or if they are the resource [owner].
///
/// [getId] and [getOwner] are passed to [restrictToOwner], along with
/// [userKey] and [errorMessage].
/// [idField], [ownerField], [userKey] and [errorMessage].
HookedServiceEventListener toHook(
{String errorMessage,
String idField,
String ownerField,
String userKey,
bool owner: false,
getRoles(user),
@ -41,6 +43,8 @@ class Permission {
// Try owner if the roles are not in-place
if (owner == true) {
var listener = restrictToOwner(
idField: idField,
ownerField: ownerField,
userKey: userKey,
errorMessage: errorMessage,
getId: getId,

View file

@ -1,5 +1,5 @@
name: angel_security
version: 0.0.5
version: 0.0.6
description: Angel middleware designed to enhance application security by patching common Web security holes.
author: Tobe O <thosakwe@gmail.com>
environment: