Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
Account
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 7
600
0.00% covered (danger)
0.00%
0 / 1
 get
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
12
 save
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 update
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 delete
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 to_public
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 from_provision
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
72
 clean_records
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
56
1<?php
2/**
3 * The site's provisioned MailChannels sub-account.
4 *
5 * @package automattic/jetpack-send
6 */
7
8namespace Automattic\Jetpack\Send;
9
10use WP_Error;
11
12if ( ! defined( 'ABSPATH' ) ) {
13    exit( 0 );
14}
15
16/**
17 * Reads and writes the `jetpack_send_account` option.
18 */
19class Account {
20
21    /**
22     * Option name.
23     *
24     * @var string
25     */
26    const OPTION = 'jetpack_send_account';
27
28    /**
29     * The stored account, or null when the site isn't set up.
30     *
31     * @return array|null
32     */
33    public static function get() {
34        $account = get_option( self::OPTION );
35        return is_array( $account ) && ! empty( $account['api_key'] ) ? $account : null;
36    }
37
38    /**
39     * Replace the stored account.
40     *
41     * @param array $account Account.
42     * @return void
43     */
44    public static function save( array $account ) {
45        update_option( self::OPTION, $account, false );
46    }
47
48    /**
49     * Merge changes into the stored account, if there is one.
50     *
51     * @param array $changes Keys to change.
52     * @return void
53     */
54    public static function update( array $changes ) {
55        $account = self::get();
56        if ( $account ) {
57            self::save( array_merge( $account, $changes ) );
58        }
59    }
60
61    /**
62     * Delete the option.
63     *
64     * @return void
65     */
66    public static function delete() {
67        delete_option( self::OPTION );
68    }
69
70    /**
71     * The account without its API key, for REST responses.
72     *
73     * @param array|null $account Account.
74     * @return array|null
75     */
76    public static function to_public( $account ) {
77        if ( ! is_array( $account ) ) {
78            return null;
79        }
80        unset( $account['api_key'] );
81        return $account;
82    }
83
84    /**
85     * Validate a provisioner result and shape it into an account.
86     *
87     * @param array  $result   Provisioner::provision() result.
88     * @param string $domain   Sending domain.
89     * @param string $provider Provisioner type.
90     * @return array|WP_Error
91     */
92    public static function from_provision( array $result, $domain, $provider ) {
93        foreach ( array( 'handle', 'api_key', 'lockdown_auth_id' ) as $key ) {
94            if ( empty( $result[ $key ] ) || ! is_string( $result[ $key ] ) ) {
95                return new WP_Error( 'jetpack_send_bad_provision', __( 'The sending account could not be created. Please try again.', 'jetpack-send-pkg' ), array( 'status' => 502 ) );
96            }
97        }
98
99        $records       = self::clean_records( $result['dns_records'] ?? array() );
100        $dkim_selector = '';
101        foreach ( $records as $record ) {
102            if ( 'dkim' === $record['purpose'] && false !== strpos( $record['name'], '._domainkey.' ) ) {
103                $dkim_selector = (string) strstr( $record['name'], '._domainkey.', true );
104            }
105        }
106
107        return array(
108            'handle'           => $result['handle'],
109            'api_key'          => $result['api_key'],
110            'lockdown_auth_id' => $result['lockdown_auth_id'],
111            'domain'           => $domain,
112            'dkim_selector'    => $dkim_selector,
113            'monthly_limit'    => isset( $result['monthly_limit'] ) ? (int) $result['monthly_limit'] : -1,
114            'dns_records'      => $records,
115            'zone_records'     => self::clean_records( $result['zone_records'] ?? array() ),
116            'provider'         => $provider,
117            'provisioned_at'   => gmdate( 'c' ),
118            'dns_check'        => null,
119        );
120    }
121
122    /**
123     * Keep well-formed DNS records, cast to strings.
124     *
125     * @param mixed $records Records from a provisioner.
126     * @return array[] `{type, name, value, purpose, optional}`.
127     */
128    private static function clean_records( $records ) {
129        $clean = array();
130        foreach ( (array) $records as $record ) {
131            if ( ! is_array( $record ) || ! isset( $record['type'] ) || ! isset( $record['name'] ) || ! isset( $record['value'] ) || ! isset( $record['purpose'] ) ) {
132                continue;
133            }
134            $clean[] = array(
135                'type'     => (string) $record['type'],
136                'name'     => (string) $record['name'],
137                'value'    => (string) $record['value'],
138                'purpose'  => (string) $record['purpose'],
139                'optional' => ! empty( $record['optional'] ),
140            );
141        }
142        return $clean;
143    }
144}