@@ -22,6 +22,9 @@ import 'models.dart';
22
22
23
23
final _logger = Logger ('pub.publisher.backend' );
24
24
25
+ /// Sanity check to limit publisherId length.
26
+ const maxPublisherIdLength = 64 ;
27
+
25
28
/// Sets the publisher backend service.
26
29
void registerPublisherBackend (PublisherBackend backend) =>
27
30
ss.register (#_publisherBackend, backend);
@@ -38,7 +41,7 @@ class PublisherBackend {
38
41
39
42
/// Loads a publisher (or returns null if it does not exists).
40
43
Future <Publisher > getPublisher (String publisherId) async {
41
- ArgumentError . checkNotNull (publisherId, 'publisherId' );
44
+ checkPublisherIdParam (publisherId);
42
45
final pKey = _db.emptyKey.append (Publisher , id: publisherId);
43
46
return await _db.lookupValue <Publisher >(pKey, orElse: () => null );
44
47
}
@@ -98,7 +101,7 @@ class PublisherBackend {
98
101
/// Loads the [PublisherMember] instance for [userId] (or returns null if it does not exists).
99
102
Future <PublisherMember > getPublisherMember (
100
103
String publisherId, String userId) async {
101
- ArgumentError . checkNotNull (publisherId, 'publisherId' );
104
+ checkPublisherIdParam (publisherId);
102
105
ArgumentError .checkNotNull (userId, 'userId' );
103
106
final mKey = _db.emptyKey
104
107
.append (Publisher , id: publisherId)
@@ -108,6 +111,7 @@ class PublisherBackend {
108
111
109
112
/// Whether the User [userId] has admin permissions on the publisher.
110
113
Future <bool > isMemberAdmin (String publisherId, String userId) async {
114
+ checkPublisherIdParam (publisherId);
111
115
ArgumentError .checkNotNull (publisherId, 'publisherId' );
112
116
if (userId == null ) return false ;
113
117
final member = await getPublisherMember (publisherId, userId);
@@ -120,6 +124,7 @@ class PublisherBackend {
120
124
String publisherId,
121
125
api.CreatePublisherRequest body,
122
126
) async {
127
+ checkPublisherIdParam (publisherId);
123
128
final user = await requireAuthenticatedUser ();
124
129
// Sanity check that domains are:
125
130
// - lowercase (because we want that in pub.dev)
@@ -133,7 +138,7 @@ class PublisherBackend {
133
138
InvalidInputException .checkStringLength (
134
139
publisherId,
135
140
'publisherId' ,
136
- maximum: 64 , // Some upper limit for sanity.
141
+ maximum: maxPublisherIdLength , // Some upper limit for sanity.
137
142
);
138
143
InvalidInputException .checkNotNull (body.accessToken, 'accessToken' );
139
144
InvalidInputException .checkStringLength (
@@ -207,6 +212,7 @@ class PublisherBackend {
207
212
208
213
/// Gets the publisher data
209
214
Future <api.PublisherInfo > getPublisherInfo (String publisherId) async {
215
+ checkPublisherIdParam (publisherId);
210
216
final p = await getPublisher (publisherId);
211
217
if (p == null ) {
212
218
throw NotFoundException ('Publisher $publisherId does not exists.' );
@@ -219,6 +225,7 @@ class PublisherBackend {
219
225
/// Handles: `PUT /api/publishers/<publisherId>`
220
226
Future <api.PublisherInfo > updatePublisher (
221
227
String publisherId, api.UpdatePublisherRequest update) async {
228
+ checkPublisherIdParam (publisherId);
222
229
if (update.description != null ) {
223
230
// limit length, if not null
224
231
InvalidInputException .checkStringLength (
@@ -301,6 +308,7 @@ class PublisherBackend {
301
308
302
309
/// Updates the contact email field of the publisher.
303
310
Future updateContactEmail (String publisherId, String contactEmail) async {
311
+ checkPublisherIdParam (publisherId);
304
312
final activeUser = await requireAuthenticatedUser ();
305
313
await requirePublisherAdmin (publisherId, activeUser.userId);
306
314
InvalidInputException .check (
@@ -323,6 +331,7 @@ class PublisherBackend {
323
331
/// Invites a user to become a publisher admin.
324
332
Future <account_api.InviteStatus > invitePublisherMember (
325
333
String publisherId, api.InviteMemberRequest invite) async {
334
+ checkPublisherIdParam (publisherId);
326
335
final activeUser = await requireAuthenticatedUser ();
327
336
final p = await requirePublisherAdmin (publisherId, activeUser.userId);
328
337
InvalidInputException .checkNotNull (invite.email, 'email' );
@@ -354,6 +363,7 @@ class PublisherBackend {
354
363
Future <List <api.PublisherMember >> listPublisherMembers (
355
364
String publisherId,
356
365
) async {
366
+ checkPublisherIdParam (publisherId);
357
367
final key = _db.emptyKey.append (Publisher , id: publisherId);
358
368
// TODO: add caching
359
369
final query = _db.query <PublisherMember >(ancestorKey: key);
@@ -370,6 +380,7 @@ class PublisherBackend {
370
380
Future <api.PublisherMembers > handleListPublisherMembers (
371
381
String publisherId,
372
382
) async {
383
+ checkPublisherIdParam (publisherId);
373
384
final user = await requireAuthenticatedUser ();
374
385
await requirePublisherAdmin (publisherId, user.userId);
375
386
return api.PublisherMembers (
@@ -380,6 +391,7 @@ class PublisherBackend {
380
391
/// The list of email addresses of the members with admin roles. The list
381
392
/// should be used to notify admins on upload events.
382
393
Future <List <String >> getAdminMemberEmails (String publisherId) async {
394
+ checkPublisherIdParam (publisherId);
383
395
final key = _db.emptyKey.append (Publisher , id: publisherId);
384
396
final query = _db.query <PublisherMember >(ancestorKey: key);
385
397
final userIds = await query.run ().map ((m) => m.userId).toList ();
@@ -389,6 +401,7 @@ class PublisherBackend {
389
401
/// Returns the membership info of a user.
390
402
Future <api.PublisherMember > publisherMemberInfo (
391
403
String publisherId, String userId) async {
404
+ checkPublisherIdParam (publisherId);
392
405
final user = await requireAuthenticatedUser ();
393
406
final p = await requirePublisherAdmin (publisherId, user.userId);
394
407
final key = p.key.append (PublisherMember , id: userId);
@@ -405,6 +418,7 @@ class PublisherBackend {
405
418
String userId,
406
419
api.UpdatePublisherMemberRequest update,
407
420
) async {
421
+ checkPublisherIdParam (publisherId);
408
422
final user = await requireAuthenticatedUser ();
409
423
final p = await requirePublisherAdmin (publisherId, user.userId);
410
424
final key = p.key.append (PublisherMember , id: userId);
@@ -436,6 +450,7 @@ class PublisherBackend {
436
450
437
451
/// Deletes a publisher's member.
438
452
Future <void > deletePublisherMember (String publisherId, String userId) async {
453
+ checkPublisherIdParam (publisherId);
439
454
final user = await requireAuthenticatedUser ();
440
455
final p = await requirePublisherAdmin (publisherId, user.userId);
441
456
if (userId == user.userId) {
@@ -460,6 +475,7 @@ class PublisherBackend {
460
475
/// A callback from consent backend, when a consent is granted.
461
476
/// Note: this will be retried when transaction fails due race conditions.
462
477
Future <void > inviteConsentGranted (String publisherId, String userId) async {
478
+ checkPublisherIdParam (publisherId);
463
479
final user = await accountBackend.lookupUserById (userId);
464
480
await withRetryTransaction (_db, (tx) async {
465
481
final key = _db.emptyKey
@@ -536,3 +552,14 @@ Future purgePublisherCache({String publisherId}) async {
536
552
}
537
553
538
554
String _publisherWebsite (String domain) => 'https://$domain /' ;
555
+
556
+ /// Verify that the [publisherId] parameter looks as acceptable input.
557
+ void checkPublisherIdParam (String publisherId) {
558
+ InvalidInputException .checkNotNull (publisherId, 'package' );
559
+ InvalidInputException .check (
560
+ publisherId.trim () == publisherId, 'Invalid publisherId.' );
561
+ InvalidInputException .check (
562
+ publisherId.contains ('.' ), 'Invalid publisherId.' );
563
+ InvalidInputException .checkStringLength (publisherId, 'publisherId' ,
564
+ minimum: 3 , maximum: 64 );
565
+ }
0 commit comments