Skip to content

Commit e4e5dea

Browse files
committed
Fix API key creation logic
1 parent ff49165 commit e4e5dea

File tree

3 files changed

+67
-56
lines changed

3 files changed

+67
-56
lines changed

app/Models/ApiKey.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class ApiKey extends Validable
5353
* @var array
5454
*/
5555
protected $casts = [
56-
'allowed_ips' => 'json',
56+
'allowed_ips' => 'array',
5757
'user_id' => 'int',
5858
'r_' . AdminAcl::RESOURCE_USERS => 'int',
5959
'r_' . AdminAcl::RESOURCE_ALLOCATIONS => 'int',
@@ -99,7 +99,8 @@ class ApiKey extends Validable
9999
'identifier' => 'required|string|size:16|unique:api_keys,identifier',
100100
'token' => 'required|string',
101101
'memo' => 'required|nullable|string|max:500',
102-
'allowed_ips' => 'nullable|json',
102+
'allowed_ips' => 'nullable|array',
103+
'allowed_ips.*' => 'string',
103104
'last_used_at' => 'nullable|date',
104105
'r_' . AdminAcl::RESOURCE_USERS => 'integer|min:0|max:3',
105106
'r_' . AdminAcl::RESOURCE_ALLOCATIONS => 'integer|min:0|max:3',

app/Models/Validable.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,12 @@ public function validate()
140140
}
141141

142142
return $this->getValidator()->setData(
143-
$this->toArray()
143+
// Trying to do self::toArray() here will leave out keys based on the whitelist/blacklist
144+
// for that model. Doing this will return all of the attributes in a format that can
145+
// properly be validated.
146+
$this->addCastAttributesToArray(
147+
$this->getAttributes(), $this->getMutatedAttributes()
148+
)
144149
)->passes();
145150
}
146151
}

resources/scripts/components/dashboard/AccountApiContainer.tsx

Lines changed: 58 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -46,62 +46,67 @@ export default () => {
4646
};
4747

4848
return (
49-
<div className={'my-10 flex'}>
49+
<div className={'my-10'}>
5050
<FlashMessageRender byKey={'account'} className={'mb-4'}/>
51-
<ContentBox title={'Create API Key'} className={'flex-1'}>
52-
<CreateApiKeyForm onKeyCreated={key => setKeys(s => ([...s!, key]))}/>
53-
</ContentBox>
54-
<ContentBox title={'API Keys'} className={'ml-10 flex-1'}>
55-
<SpinnerOverlay visible={loading}/>
56-
{deleteIdentifier &&
57-
<ConfirmationModal
58-
title={'Confirm key deletion'}
59-
buttonText={'Yes, delete key'}
60-
visible={true}
61-
onConfirmed={() => {
62-
doDeletion(deleteIdentifier);
63-
setDeleteIdentifier('');
64-
}}
65-
onDismissed={() => setDeleteIdentifier('')}
66-
>
67-
Are you sure you wish to delete this API key? All requests using it will immediately be
68-
invalidated and will fail.
69-
</ConfirmationModal>
70-
}
71-
{
72-
keys.length === 0 ?
73-
<p className={'text-center text-sm'}>
74-
{loading ? 'Loading...' : 'No API keys exist for this account.'}
75-
</p>
76-
:
77-
keys.map(key => (
78-
<div key={key.identifier} className={'grey-row-box bg-neutral-600 mb-2 flex items-center'}>
79-
<FontAwesomeIcon icon={faKey} className={'text-neutral-300'}/>
80-
<div className={'ml-4 flex-1'}>
81-
<p className={'text-sm'}>{key.description}</p>
82-
<p className={'text-2xs text-neutral-300 uppercase'}>
83-
Last
84-
used: {key.lastUsedAt ? format(key.lastUsedAt, 'MMM Do, YYYY HH:mm') : 'Never'}
51+
<div className={'flex'}>
52+
<ContentBox title={'Create API Key'} className={'flex-1'}>
53+
<CreateApiKeyForm onKeyCreated={key => setKeys(s => ([ ...s!, key ]))}/>
54+
</ContentBox>
55+
<ContentBox title={'API Keys'} className={'ml-10 flex-1'}>
56+
<SpinnerOverlay visible={loading}/>
57+
{deleteIdentifier &&
58+
<ConfirmationModal
59+
title={'Confirm key deletion'}
60+
buttonText={'Yes, delete key'}
61+
visible={true}
62+
onConfirmed={() => {
63+
doDeletion(deleteIdentifier);
64+
setDeleteIdentifier('');
65+
}}
66+
onDismissed={() => setDeleteIdentifier('')}
67+
>
68+
Are you sure you wish to delete this API key? All requests using it will immediately be
69+
invalidated and will fail.
70+
</ConfirmationModal>
71+
}
72+
{
73+
keys.length === 0 ?
74+
<p className={'text-center text-sm'}>
75+
{loading ? 'Loading...' : 'No API keys exist for this account.'}
76+
</p>
77+
:
78+
keys.map(key => (
79+
<div
80+
key={key.identifier}
81+
className={'grey-row-box bg-neutral-600 mb-2 flex items-center'}
82+
>
83+
<FontAwesomeIcon icon={faKey} className={'text-neutral-300'}/>
84+
<div className={'ml-4 flex-1'}>
85+
<p className={'text-sm'}>{key.description}</p>
86+
<p className={'text-2xs text-neutral-300 uppercase'}>
87+
Last
88+
used: {key.lastUsedAt ? format(key.lastUsedAt, 'MMM Do, YYYY HH:mm') : 'Never'}
89+
</p>
90+
</div>
91+
<p className={'text-sm ml-4'}>
92+
<code className={'font-mono py-1 px-2 bg-neutral-900 rounded'}>
93+
{key.identifier}
94+
</code>
8595
</p>
96+
<button
97+
className={'ml-4 p-2 text-sm'}
98+
onClick={() => setDeleteIdentifier(key.identifier)}
99+
>
100+
<FontAwesomeIcon
101+
icon={faTrashAlt}
102+
className={'text-neutral-400 hover:text-red-400 transition-colors duration-150'}
103+
/>
104+
</button>
86105
</div>
87-
<p className={'text-sm ml-4'}>
88-
<code className={'font-mono py-1 px-2 bg-neutral-900 rounded'}>
89-
{key.identifier}
90-
</code>
91-
</p>
92-
<button
93-
className={'ml-4 p-2 text-sm'}
94-
onClick={() => setDeleteIdentifier(key.identifier)}
95-
>
96-
<FontAwesomeIcon
97-
icon={faTrashAlt}
98-
className={'text-neutral-400 hover:text-red-400 transition-colors duration-150'}
99-
/>
100-
</button>
101-
</div>
102-
))
103-
}
104-
</ContentBox>
106+
))
107+
}
108+
</ContentBox>
109+
</div>
105110
</div>
106111
);
107112
};

0 commit comments

Comments
 (0)