Skip to content

Commit 5f75b37

Browse files
authored
Merge pull request #138 from dshanske/expire
Add Bulk Actions and Improve List/Token Generation
2 parents 44246d9 + ccc64fe commit 5f75b37

File tree

8 files changed

+288
-125
lines changed

8 files changed

+288
-125
lines changed

includes/class-indieauth-authorization-endpoint.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public function register_routes() {
6363
}
6464

6565
// Get Scope Descriptions
66-
public function scopes( $scope = 'all' ) {
66+
public static function scopes( $scope = 'all' ) {
6767
$scopes = array(
6868
// Micropub Scopes
6969
'post' => __( 'Legacy Scope (Deprecated)', 'indieauth' ),

includes/class-indieauth-token-ui.php

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,13 @@ public function new_token() {
5454
exit;
5555
}
5656
require ABSPATH . 'wp-admin/admin-header.php';
57-
$token = self::generate_local_token( $_REQUEST['client_name'] );
57+
$client_name = sanitize_text_field( $_REQUEST['client_name'] );
58+
$scopes = trim( implode( ' ', $_REQUEST['scopes'] ) );
59+
if ( empty( $scopes ) ) {
60+
$scopes = 'create update';
61+
}
62+
$scopes = sanitize_text_field( $scopes );
63+
$token = self::generate_local_token( $client_name, $scopes );
5864
?>
5965
<p><?php esc_html_e( 'A token has been generated and appears below. This token will not be stored anywhere. Please copy and store it.', 'indieauth' ); ?></p>
6066
<h3><?php echo $token; // phpcs:ignore
@@ -65,13 +71,13 @@ public function new_token() {
6571
exit;
6672
}
6773

68-
private function generate_local_token( $name ) {
74+
private function generate_local_token( $name, $scopes ) {
6975
$user_id = get_current_user_id();
7076
$tokens = new Token_User( '_indieauth_token_' );
7177
$tokens->set_user( $user_id );
7278
$token = array(
7379
'token_type' => 'Bearer',
74-
'scope' => 'create update',
80+
'scope' => $scopes,
7581
'me' => get_the_author_meta( 'user_url', $user_id ) ? get_the_author_meta( 'user_url', $user_id ) : get_author_posts_url( $user_id ),
7682
'issued_by' => rest_url( 'indieauth/1.0/token' ),
7783
'user' => $user_id,
@@ -96,22 +102,36 @@ public function options_form() {
96102
$codes->check_expires();
97103
$token_table = new Token_List_Table();
98104
echo '<div class="wrap"><h2>' . esc_html__( 'Manage IndieAuth Tokens', 'indieauth' ) . '</h2>';
105+
echo '<form method="get">';
106+
echo '<input type="hidden" name="page" value="indieauth_user_token" />';
99107
$token_table->prepare_items();
100108
$token_table->display();
109+
echo '</form>';
101110
?>
102111
</div>
103112
<div>
104113
<h3><?php esc_html_e( 'Add Token', 'indieauth' ); ?></h3>
105114
<form method="post" action="admin.php">
106115
<label for="client_name"><?php esc_html_e( 'Name for Token', 'indieauth' ); ?></label><input type="text" class="widefat" id="client_name" name="client_name" />
107-
<?php wp_nonce_field( 'indieauth_newtoken', 'indieauth_nonce' ); ?>
116+
<?php wp_nonce_field( 'indieauth_newtoken', 'indieauth_nonce' ); ?>
108117
<input type="hidden" name="action" id="action" value="indieauth_newtoken" />
118+
<h4><?php esc_html_e( 'Scopes', 'indieauth' ); ?></h4>
119+
<?php echo esc_html( $this->scopes() ); ?>
109120
<p><button class="button-primary"><?php esc_html_e( 'Add New Token', 'indieauth' ); ?></button></p>
110121
</form>
111122
</div>
112123
<?php
113124
}
114125

126+
public function scopes() {
127+
$scopes = IndieAuth_Authorization_Endpoint::scopes();
128+
echo '<ul>';
129+
foreach ( $scopes as $scope => $description ) {
130+
printf( '<li><input type="checkbox" name="scopes[]" value="%1$s" /><strong>%1$s</strong> - %2$s</li>', esc_attr( $scope ), esc_html( $description ) );
131+
}
132+
echo '</ul>';
133+
}
134+
115135
/**
116136
* Is prefix in string.
117137
*

includes/class-token-generic.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ protected function generate_token() {
4444
* @return int Timestamp when this will expire.
4545
*/
4646
public function expires( $expiration ) {
47-
return $this->time() + $expiration;
47+
return time() + $expiration;
4848
}
4949

5050
/**
@@ -66,7 +66,7 @@ public function is_expired( $expiration ) {
6666
if ( ! is_numeric( $expiration ) ) {
6767
return false;
6868
}
69-
return ( $expiration <= $this->time() );
69+
return ( $expiration <= time() );
7070
}
7171

7272

includes/class-token-list-table.php

Lines changed: 107 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,29 @@
77
class Token_List_Table extends WP_List_Table {
88
public function get_columns() {
99
return array(
10+
'cb' => '<input type="checkbox" />',
1011
'client_name' => __( 'Client Name', 'indieauth' ),
1112
'client_icon' => __( 'Client Icon', 'indieauth' ),
1213
'client_id' => __( 'Client ID', 'indieauth' ),
1314
'scope' => __( 'Scope', 'indieauth' ),
1415
'issued_at' => __( 'Issue Date', 'indieauth' ),
1516
'last_accessed' => __( 'Last Accessed', 'indieauth' ),
17+
'expiration' => __( 'Expires', 'indieauth' ),
1618
);
1719
}
1820

21+
public function get_bulk_actions() {
22+
return array(
23+
'revoke' => __( 'Revoke', 'indieauth' ),
24+
'revoke_year' => __( 'Revoke Tokens Last Accessed 1 Year Ago or Never', 'indieauth' ),
25+
'revoke_month' => __( 'Revoke Tokens Last Accessed 1 Month Ago or Never', 'indieauth' ),
26+
'revoke_week' => __( 'Revoke Tokens Last Accessed 1 Week Ago or Never', 'indieauth' ),
27+
'revoke_day' => __( 'Revoke Tokens Last Accessed 1 Day Ago or Never', 'indieauth' ),
28+
'revoke_hour' => __( 'Revoke Tokens Last Accessed 1 Hour Ago or Never', 'indieauth' ),
29+
'cleanup' => __( 'Clean Up Expired Tokens and Authorization Codes', 'indieauth' ),
30+
);
31+
}
32+
1933
public function get_sortable_columns() {
2034
return array();
2135
}
@@ -32,37 +46,95 @@ public function prepare_items() {
3246
$value['token'] = $key;
3347
$this->items[] = $value;
3448
}
49+
3550
}
3651

3752
public function column_default( $item, $column_name ) {
3853
return $item[ $column_name ];
3954
}
4055

56+
public function column_cb( $item ) {
57+
return sprintf( '<input type="checkbox" name="tokens[]" value="%s" />', esc_attr( $item['token'] ) );
58+
}
59+
4160
public function process_action() {
42-
$tokens = isset( $_GET['tokens'] ) ? $_GET['tokens'] : array(); // phpcs:ignore
61+
$tokens = isset( $_REQUEST['tokens'] ) ? $_REQUEST['tokens'] : array(); // phpcs:ignore
4362
$t = new Token_User( '_indieauth_token_', get_current_user_id() );
44-
if ( 'revoke' === $this->current_action() ) {
45-
if ( is_string( $tokens ) ) {
46-
$t->destroy( $tokens );
47-
} elseif ( is_array( $tokens ) ) {
48-
foreach ( $tokens as $token ) {
49-
$t->destroy( $token );
63+
switch ( $this->current_action() ) {
64+
case 'revoke':
65+
if ( is_string( $tokens ) ) {
66+
$t->destroy( $tokens );
67+
} elseif ( is_array( $tokens ) ) {
68+
foreach ( $tokens as $token ) {
69+
$t->destroy( $token );
70+
}
5071
}
51-
}
52-
}
53-
if ( 'retrieve' === $this->current_action() ) {
54-
if ( is_string( $tokens ) ) {
55-
$token = $t->get( $tokens, false );
56-
$info = new IndieAuth_Client_Discovery( $token['client_id'] );
57-
$name = $info->get_name();
58-
if ( isset( $name ) ) {
59-
$token['client_name'] = $name;
72+
break;
73+
case 'cleanup':
74+
$t->check_expires();
75+
$users = new Token_User( '_indieauth_code_', get_current_user_id() );
76+
$users->destroy_all();
77+
break;
78+
case 'revoke_year':
79+
$this->destroy_older_than( $t, 'year' );
80+
break;
81+
case 'revoke_month':
82+
$this->destroy_older_than( $t, 'month' );
83+
break;
84+
case 'revoke_week':
85+
$this->destroy_older_than( $t, 'week' );
86+
break;
87+
case 'revoke_day':
88+
$this->destroy_older_than( $t, 'day' );
89+
break;
90+
case 'revoke_hour':
91+
$this->destroy_older_than( $t, 'hour' );
92+
break;
93+
case 'retrieve':
94+
if ( is_string( $tokens ) ) {
95+
$token = $t->get( $tokens, false );
96+
$info = new IndieAuth_Client_Discovery( $token['client_id'] );
97+
$name = $info->get_name();
98+
if ( isset( $name ) ) {
99+
$token['client_name'] = $name;
100+
}
101+
$icon = $info->get_icon();
102+
if ( isset( $icon ) ) {
103+
$token['client_icon'] = $icon;
104+
}
105+
$t->update( $tokens, $token, true );
60106
}
61-
$icon = $info->get_icon();
62-
if ( isset( $icon ) ) {
63-
$token['client_icon'] = $icon;
107+
break;
108+
}
109+
}
110+
111+
public function destroy_older_than( $t, $older_than = 'day' ) {
112+
switch ( strtolower( $older_than ) ) {
113+
case 'year':
114+
$diff = YEAR_IN_SECONDS;
115+
break;
116+
case 'month':
117+
$diff = MONTH_IN_SECONDS;
118+
break;
119+
case 'week':
120+
$diff = WEEK_IN_SECONDS;
121+
break;
122+
case 'day':
123+
$diff = DAY_IN_SECONDS;
124+
break;
125+
default:
126+
$diff = HOUR_IN_SECONDS;
127+
}
128+
$tokens = $t->get_all();
129+
foreach ( $tokens as $key => $token ) {
130+
if ( ! isset( $token['last_accessed'] ) ) {
131+
$t->destroy( $key );
132+
} else {
133+
$time = (int) $token['last_accessed'];
134+
$time_diff = time() - $time;
135+
if ( $time_diff > 0 && $time_diff > $diff ) {
136+
$t->destroy( $key );
64137
}
65-
$t->update( $tokens, $token, true );
66138
}
67139
}
68140
}
@@ -99,6 +171,21 @@ public function column_last_accessed( $item ) {
99171
return date_i18n( get_option( 'date_format' ), $time );
100172
}
101173

174+
175+
public function column_expiration( $item ) {
176+
if ( ! isset( $item['expiration'] ) ) {
177+
return __( 'Never', 'indieauth' );
178+
}
179+
$time = (int) $item['expiration'];
180+
$time_diff = time() - $time;
181+
if ( $time_diff > 0 && $time_diff < DAY_IN_SECONDS ) {
182+
// translators: Human time difference ago
183+
return sprintf( __( '%s ago', 'indieauth' ), human_time_diff( $time ) );
184+
}
185+
return date_i18n( get_option( 'date_format' ), $time );
186+
}
187+
188+
102189
public function column_issued_at( $item ) {
103190
return date_i18n( get_option( 'date_format' ), $item['issued_at'] );
104191
}

includes/class-token-user.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,24 @@ public function destroy( $key ) {
6868
}
6969
}
7070

71+
/**
72+
* Destroys all tokens
73+
*
74+
* @return boolean Return if successfully destroyed or not
75+
*/
76+
public function destroy_all() {
77+
if ( ! $this->user_id ) {
78+
return false;
79+
}
80+
$meta = get_user_meta( $this->user_id, '' );
81+
foreach ( array_keys( $meta ) as $key ) {
82+
if ( 0 === strncmp( $key, $this->prefix, strlen( $this->prefix ) ) ) {
83+
delete_user_meta( $this->user_id, $key );
84+
}
85+
}
86+
}
87+
88+
7189
/**
7290
* Retrieves all tokens for a user
7391
*

0 commit comments

Comments
 (0)