Completed
Push — develop ( 686594...b5844e )
by Florent
03:11
created

testCreateFlattenedJWEUsingFactory()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 36
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 36
rs 8.8571
cc 1
eloc 23
nc 1
nop 0
1
<?php
2
3
/*
4
 * The MIT License (MIT)
5
 *
6
 * Copyright (c) 2014-2016 Spomky-Labs
7
 *
8
 * This software may be modified and distributed under the terms
9
 * of the MIT license.  See the LICENSE file for details.
10
 */
11
12
use Base64Url\Base64Url;
13
use Jose\Factory\DecrypterFactory;
14
use Jose\Factory\EncrypterFactory;
15
use Jose\Factory\JWEFactory;
16
use Jose\Loader;
17
use Jose\Object\JWEInterface;
18
use Jose\Object\JWK;
19
use Jose\Object\JWKSet;
20
use Jose\Test\Stub\FakeLogger;
21
use Jose\Test\TestCase;
22
23
/**
24
 * Class EncrypterTest.
25
 *
26
 * @group Encrypter
27
 * @group Functional
28
 */
29
class EncrypterTest extends TestCase
30
{
31
    public function testEncryptWithJWTInput()
32
    {
33
        $encrypter = EncrypterFactory::createEncrypter(['RSA-OAEP-256', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
34
        $decrypter = DecrypterFactory::createDecrypter(['RSA-OAEP-256', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
35
36
        $jwe = JWEFactory::createJWE(
37
            'FOO',
38
            [
39
                'enc' => 'A256CBC-HS512',
40
                'alg' => 'RSA-OAEP-256',
41
                'zip' => 'DEF',
42
            ],
43
            [],
44
            'foo,bar,baz'
45
        );
46
47
        $jwe = $jwe->addRecipient($this->getRSARecipientKey());
48
49
        $encrypter->encrypt($jwe);
50
51
        $encrypted = $jwe->toFlattenedJSON(0);
52
53
        $loaded = Loader::load($encrypted);
54
55
        $this->assertInstanceOf(JWEInterface::class, $loaded);
56
        $this->assertEquals('RSA-OAEP-256', $loaded->getSharedProtectedHeader('alg'));
0 ignored issues
show
Bug introduced by
The method getSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
57
        $this->assertEquals('A256CBC-HS512', $loaded->getSharedProtectedHeader('enc'));
58
        $this->assertEquals('DEF', $loaded->getSharedProtectedHeader('zip'));
59
        $this->assertNull($loaded->getPayload());
60
61
        $decrypter->decryptUsingKeySet($loaded, $this->getPrivateKeySet(), $index);
0 ignored issues
show
Bug introduced by
It seems like $loaded defined by \Jose\Loader::load($encrypted) on line 53 can also be of type object<Jose\Object\JWSInterface>; however, Jose\Decrypter::decryptUsingKeySet() does only seem to accept object<Jose\Object\JWEInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
62
63
        $this->assertEquals(0, $index);
64
        $this->assertEquals('FOO', $loaded->getPayload());
65
    }
66
67
    public function testCreateCompactJWEUsingFactory()
68
    {
69
        $jwe = JWEFactory::createJWEToCompactJSON(
70
            'FOO',
71
            $this->getRSARecipientKey(),
72
            [
73
                'enc' => 'A256CBC-HS512',
74
                'alg' => 'RSA-OAEP-256',
75
                'zip' => 'DEF',
76
            ]
77
        );
78
79
        $loaded = Loader::load($jwe);
80
81
        $this->assertInstanceOf(JWEInterface::class, $loaded);
82
        $this->assertEquals('RSA-OAEP-256', $loaded->getSharedProtectedHeader('alg'));
0 ignored issues
show
Bug introduced by
The method getSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
83
        $this->assertEquals('A256CBC-HS512', $loaded->getSharedProtectedHeader('enc'));
84
        $this->assertEquals('DEF', $loaded->getSharedProtectedHeader('zip'));
85
        $this->assertNull($loaded->getPayload());
86
87
        $decrypter = DecrypterFactory::createDecrypter(['RSA-OAEP-256', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
88
        $decrypter->decryptUsingKeySet($loaded, $this->getPrivateKeySet(), $index);
0 ignored issues
show
Bug introduced by
It seems like $loaded defined by \Jose\Loader::load($jwe) on line 79 can also be of type object<Jose\Object\JWSInterface>; however, Jose\Decrypter::decryptUsingKeySet() does only seem to accept object<Jose\Object\JWEInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
89
90
        $this->assertEquals(0, $index);
91
        $this->assertEquals('FOO', $loaded->getPayload());
92
    }
93
94
    public function testCreateFlattenedJWEUsingFactory()
95
    {
96
        $jwe = JWEFactory::createJWEToFlattenedJSON(
97
            'FOO',
98
            $this->getRSARecipientKey(),
99
            [
100
                'enc' => 'A256CBC-HS512',
101
                'alg' => 'RSA-OAEP-256',
102
                'zip' => 'DEF',
103
            ],
104
            [
105
                'foo' => 'bar',
106
            ],
107
            [
108
                'plic' => 'ploc',
109
            ],
110
            'A,B,C,D'
111
        );
112
113
        $loaded = Loader::load($jwe);
114
115
        $this->assertInstanceOf(JWEInterface::class, $loaded);
116
        $this->assertEquals('RSA-OAEP-256', $loaded->getSharedProtectedHeader('alg'));
0 ignored issues
show
Bug introduced by
The method getSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
117
        $this->assertEquals('A256CBC-HS512', $loaded->getSharedProtectedHeader('enc'));
118
        $this->assertEquals('DEF', $loaded->getSharedProtectedHeader('zip'));
119
        $this->assertEquals('bar', $loaded->getSharedHeader('foo'));
0 ignored issues
show
Bug introduced by
The method getSharedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
120
        $this->assertEquals('A,B,C,D', $loaded->getAAD('foo'));
0 ignored issues
show
Unused Code introduced by
The call to JWEInterface::getAAD() has too many arguments starting with 'foo'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
Bug introduced by
The method getAAD does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
121
        $this->assertEquals('ploc', $loaded->getRecipient(0)->getHeader('plic'));
0 ignored issues
show
Bug introduced by
The method getRecipient does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
122
        $this->assertNull($loaded->getPayload());
123
124
        $decrypter = DecrypterFactory::createDecrypter(['RSA-OAEP-256', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
125
        $decrypter->decryptUsingKeySet($loaded, $this->getPrivateKeySet(), $index);
0 ignored issues
show
Bug introduced by
It seems like $loaded defined by \Jose\Loader::load($jwe) on line 113 can also be of type object<Jose\Object\JWSInterface>; however, Jose\Decrypter::decryptUsingKeySet() does only seem to accept object<Jose\Object\JWEInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
126
127
        $this->assertEquals(0, $index);
128
        $this->assertEquals('FOO', $loaded->getPayload());
129
    }
130
131
    public function testEncryptAndLoadFlattenedWithAAD()
132
    {
133
        $encrypter = EncrypterFactory::createEncrypter(['RSA-OAEP-256', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
134
        $decrypter = DecrypterFactory::createDecrypter(['RSA-OAEP-256', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
135
136
        $jwe = JWEFactory::createJWE(
137
            $this->getKeyToEncrypt(),
138
            [
139
                'enc' => 'A256CBC-HS512',
140
                'alg' => 'RSA-OAEP-256',
141
                'zip' => 'DEF',
142
            ],
143
            [],
144
            'foo,bar,baz'
145
        );
146
147
        $jwe = $jwe->addRecipient($this->getRSARecipientKey());
148
149
        $encrypter->encrypt($jwe);
150
151
        $encrypted = $jwe->toFlattenedJSON(0);
152
153
        $loaded = Loader::load($encrypted);
154
155
        $this->assertInstanceOf(JWEInterface::class, $loaded);
156
        $this->assertEquals('RSA-OAEP-256', $loaded->getSharedProtectedHeader('alg'));
0 ignored issues
show
Bug introduced by
The method getSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
157
        $this->assertEquals('A256CBC-HS512', $loaded->getSharedProtectedHeader('enc'));
158
        $this->assertEquals('DEF', $loaded->getSharedProtectedHeader('zip'));
159
        $this->assertNull($loaded->getPayload());
160
161
        $decrypter->decryptUsingKeySet($loaded, $this->getPrivateKeySet(), $index);
0 ignored issues
show
Bug introduced by
It seems like $loaded defined by \Jose\Loader::load($encrypted) on line 153 can also be of type object<Jose\Object\JWSInterface>; however, Jose\Decrypter::decryptUsingKeySet() does only seem to accept object<Jose\Object\JWEInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
162
163
        $this->assertEquals(0, $index);
164
        $this->assertTrue(is_array($loaded->getPayload()));
165
        $this->assertEquals($this->getKeyToEncrypt(), new JWK($loaded->getPayload()));
0 ignored issues
show
Documentation introduced by
$loaded->getPayload() is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
166
    }
167
168
    /**
169
     * @expectedException \InvalidArgumentException
170
     * @expectedExceptionMessage Compression method "FIP" not supported
171
     */
172
    public function testCompressionAlgorithmNotSupported()
173
    {
174
        $encrypter = EncrypterFactory::createEncrypter(['RSA-OAEP-256', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
175
176
        $jwe = JWEFactory::createJWE(
177
            $this->getKeyToEncrypt(),
178
            [
179
                'enc' => 'A256CBC-HS512',
180
                'alg' => 'RSA-OAEP-256',
181
                'zip' => 'FIP',
182
            ],
183
            [],
184
            'foo,bar,baz'
185
        );
186
187
        $jwe = $jwe->addRecipient($this->getRSARecipientKey());
188
189
        $encrypter->encrypt($jwe);
190
    }
191
192
    public function testMultipleInstructionsNotAllowedWithCompactSerialization()
193
    {
194
        $encrypter = EncrypterFactory::createEncrypter(['RSA-OAEP', 'RSA-OAEP-256', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
195
196
        $jwe = JWEFactory::createJWE('Live long and Prosper.');
197
        $jwe = $jwe->withSharedProtectedHeaders([
198
            'enc' => 'A256CBC-HS512',
199
        ]);
200
201
        $jwe = $jwe->addRecipient($this->getRSARecipientKeyWithAlgorithm(), ['alg' => 'RSA-OAEP']);
202
        $jwe = $jwe->addRecipient($this->getRSARecipientKey(), ['alg' => 'RSA-OAEP-256']);
203
204
        $encrypter->encrypt($jwe);
205
206
        $this->assertEquals(2, $jwe->countRecipients());
207
    }
208
209
    public function testMultipleInstructionsNotAllowedWithFlattenedSerialization()
210
    {
211
        $encrypter = EncrypterFactory::createEncrypter(['RSA-OAEP-256', 'ECDH-ES+A256KW', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
212
213
        $jwe = JWEFactory::createJWE('Live long and Prosper.');
214
        $jwe = $jwe->withSharedProtectedHeaders([
215
            'enc' => 'A256CBC-HS512',
216
        ]);
217
218
        $jwe = $jwe->addRecipient(
219
            $this->getECDHRecipientPublicKey(),
220
            ['kid' => 'e9bc097a-ce51-4036-9562-d2ade882db0d', 'alg' => 'ECDH-ES+A256KW']
221
        );
222
        $jwe = $jwe->addRecipient(
223
            $this->getRSARecipientKey(),
224
            ['kid' => '123456789', 'alg' => 'RSA-OAEP-256']
225
        );
226
227
        $encrypter->encrypt($jwe);
228
229
        $this->assertEquals(2, $jwe->countRecipients());
230
    }
231
232
    /**
233
     * @expectedException \InvalidArgumentException
234
     * @expectedExceptionMessage Foreign key management mode forbidden.
235
     */
236
    public function testForeignKeyManagementModeForbidden()
237
    {
238
        $encrypter = EncrypterFactory::createEncrypter(['dir', 'ECDH-ES+A256KW', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
239
240
        $jwe = JWEFactory::createJWE('Live long and Prosper.');
241
        $jwe = $jwe->withSharedProtectedHeaders([
242
            'enc' => 'A256CBC-HS512',
243
        ]);
244
245
        $jwe = $jwe->addRecipient(
246
            $this->getECDHRecipientPublicKey(),
247
            ['kid' => 'e9bc097a-ce51-4036-9562-d2ade882db0d', 'alg' => 'ECDH-ES+A256KW']
248
        );
249
        $jwe = $jwe->addRecipient(
250
            $this->getDirectKey(),
251
            ['kid' => 'DIR_1', 'alg' => 'dir']
252
        );
253
254
        $encrypter->encrypt($jwe);
255
    }
256
257
    /**
258
     * @expectedException \InvalidArgumentException
259
     * @expectedExceptionMessage Key cannot be used to encrypt
260
     */
261
    public function testOperationNotAllowedForTheKey()
262
    {
263
        $encrypter = EncrypterFactory::createEncrypter(['RSA-OAEP-256', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
264
265
        $jwe = JWEFactory::createJWE(
266
            'Foo',
267
            [
268
                'enc' => 'A256CBC-HS512',
269
                'alg' => 'RSA-OAEP-256',
270
                'zip' => 'DEF',
271
            ],
272
            [],
273
            'foo,bar,baz'
274
        );
275
        $jwe = $jwe->addRecipient(
276
            $this->getSigningKey()
277
        );
278
279
        $encrypter->encrypt($jwe);
280
    }
281
282
    /**
283
     * @expectedException \InvalidArgumentException
284
     * @expectedExceptionMessage Key is only allowed for algorithm "RSA-OAEP".
285
     */
286
    public function testAlgorithmNotAllowedForTheKey()
287
    {
288
        $encrypter = EncrypterFactory::createEncrypter(['RSA-OAEP-256', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
289
290
        $jwe = JWEFactory::createJWE(
291
            'FOO',
292
            [
293
                'enc' => 'A256CBC-HS512',
294
                'alg' => 'RSA-OAEP-256',
295
                'zip' => 'DEF',
296
            ],
297
            [],
298
            'foo,bar,baz'
299
        );
300
        $jwe = $jwe->addRecipient(
301
            $this->getRSARecipientKeyWithAlgorithm()
302
        );
303
304
        $encrypter->encrypt($jwe);
305
    }
306
307
    public function testEncryptAndLoadFlattenedWithDeflateCompression()
308
    {
309
        $encrypter = EncrypterFactory::createEncrypter(['RSA-OAEP-256', 'A128CBC-HS256'], ['DEF'], new FakeLogger());
310
        $decrypter = DecrypterFactory::createDecrypter(['RSA-OAEP-256', 'A128CBC-HS256'], ['DEF'], new FakeLogger());
311
312
        $jwe = JWEFactory::createJWE($this->getKeyToEncrypt());
313
        $jwe = $jwe->withSharedProtectedHeaders([
314
            'kid' => '123456789',
315
            'enc' => 'A128CBC-HS256',
316
            'alg' => 'RSA-OAEP-256',
317
            'zip' => 'DEF',
318
        ]);
319
        $jwe = $jwe->addRecipient(
320
            $this->getRSARecipientKey()
321
        );
322
323
        $encrypter->encrypt($jwe);
324
325
        $encrypted = $jwe->toCompactJSON(0);
326
327
        $loaded = Loader::load($encrypted);
328
329
        $this->assertInstanceOf(JWEInterface::class, $loaded);
330
        $this->assertEquals('RSA-OAEP-256', $loaded->getSharedProtectedHeader('alg'));
0 ignored issues
show
Bug introduced by
The method getSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
331
        $this->assertEquals('A128CBC-HS256', $loaded->getSharedProtectedHeader('enc'));
332
        $this->assertEquals('DEF', $loaded->getSharedProtectedHeader('zip'));
333
        $this->assertNull($loaded->getPayload());
334
335
        $decrypter->decryptUsingKeySet($loaded, $this->getPrivateKeySet(), $index);
0 ignored issues
show
Bug introduced by
It seems like $loaded defined by \Jose\Loader::load($encrypted) on line 327 can also be of type object<Jose\Object\JWSInterface>; however, Jose\Decrypter::decryptUsingKeySet() does only seem to accept object<Jose\Object\JWEInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
336
337
        $this->assertEquals(0, $index);
338
        $this->assertTrue(is_array($loaded->getPayload()));
339
        $this->assertEquals($this->getKeySetToEncrypt(), new JWKSet($loaded->getPayload()));
0 ignored issues
show
Documentation introduced by
$loaded->getPayload() is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
340
    }
341
342
    /**
343
     * @expectedException \InvalidArgumentException
344
     * @expectedExceptionMessage Parameter "alg" is missing.
345
     */
346
    public function testAlgParameterIsMissing()
347
    {
348
        $encrypter = EncrypterFactory::createEncrypter(['A256CBC-HS512'], ['DEF'], new FakeLogger());
349
350
        $jwe = JWEFactory::createJWE($this->getKeyToEncrypt());
351
        $jwe = $jwe->withSharedProtectedHeaders([
352
            'kid' => '123456789',
353
            'enc' => 'A256CBC-HS512',
354
            'zip' => 'DEF',
355
        ]);
356
        $jwe = $jwe->addRecipient(
357
            $this->getRSARecipientKey()
358
        );
359
360
        $encrypter->encrypt($jwe);
361
    }
362
363
    /**
364
     * @expectedException \InvalidArgumentException
365
     * @expectedExceptionMessage Parameter "enc" is missing.
366
     */
367
    public function testEncParameterIsMissing()
368
    {
369
        $encrypter = EncrypterFactory::createEncrypter(['RSA-OAEP-256'], ['DEF'], new FakeLogger());
370
371
        $jwe = JWEFactory::createJWE($this->getKeyToEncrypt());
372
        $jwe = $jwe->withSharedProtectedHeaders([
373
            'kid' => '123456789',
374
            'alg' => 'RSA-OAEP-256',
375
            'zip' => 'DEF',
376
        ]);
377
        $jwe = $jwe->addRecipient(
378
            $this->getRSARecipientKey()
379
        );
380
381
        $encrypter->encrypt($jwe);
382
    }
383
384
    /**
385
     * @expectedException \InvalidArgumentException
386
     * @expectedExceptionMessage The key encryption algorithm "A256CBC-HS512" is not supported or not a key encryption algorithm instance.
387
     */
388
    public function testNotAKeyEncryptionAlgorithm()
389
    {
390
        $encrypter = EncrypterFactory::createEncrypter(['A256CBC-HS512'], ['DEF'], new FakeLogger());
391
392
        $jwe = JWEFactory::createJWE($this->getKeyToEncrypt());
393
        $jwe = $jwe->withSharedProtectedHeaders([
394
            'kid' => '123456789',
395
            'enc' => 'A256CBC-HS512',
396
            'alg' => 'A256CBC-HS512',
397
            'zip' => 'DEF',
398
        ]);
399
        $jwe = $jwe->addRecipient(
400
            $this->getRSARecipientKey()
401
        );
402
403
        $encrypter->encrypt($jwe);
404
    }
405
406
    /**
407
     * @expectedException \InvalidArgumentException
408
     * @expectedExceptionMessage The content encryption algorithm "RSA-OAEP-256" is not supported or not a content encryption algorithm instance.
409
     */
410
    public function testNotAContentEncryptionAlgorithm()
411
    {
412
        $encrypter = EncrypterFactory::createEncrypter(['RSA-OAEP-256'], ['DEF'], new FakeLogger());
413
414
        $jwe = JWEFactory::createJWE($this->getKeyToEncrypt());
415
        $jwe = $jwe->withSharedProtectedHeaders([
416
            'kid' => '123456789',
417
            'enc' => 'RSA-OAEP-256',
418
            'alg' => 'RSA-OAEP-256',
419
            'zip' => 'DEF',
420
        ]);
421
422
        $jwe = $jwe->addRecipient(
423
            $this->getRSARecipientKey()
424
        );
425
426
        $encrypter->encrypt($jwe);
427
    }
428
429
    public function testEncryptAndLoadCompactWithDirectKeyEncryption()
430
    {
431
        $encrypter = EncrypterFactory::createEncrypter(['dir', 'A192CBC-HS384'], ['DEF'], new FakeLogger());
432
        $decrypter = DecrypterFactory::createDecrypter(['dir', 'A192CBC-HS384'], ['DEF'], new FakeLogger());
433
434
        $jwe = JWEFactory::createJWE($this->getKeyToEncrypt());
435
        $jwe = $jwe->withSharedProtectedHeaders([
436
            'kid' => 'DIR_1',
437
            'enc' => 'A192CBC-HS384',
438
            'alg' => 'dir',
439
        ]);
440
441
        $jwe = $jwe->addRecipient(
442
            $this->getDirectKey()
443
        );
444
445
        $encrypter->encrypt($jwe);
446
447
        $encrypted = $jwe->toFlattenedJSON(0);
448
449
        $loaded = Loader::load($encrypted);
450
451
        $this->assertInstanceOf(JWEInterface::class, $loaded);
452
        $this->assertEquals('dir', $loaded->getSharedProtectedHeader('alg'));
0 ignored issues
show
Bug introduced by
The method getSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
453
        $this->assertEquals('A192CBC-HS384', $loaded->getSharedProtectedHeader('enc'));
454
        $this->assertFalse($loaded->hasSharedHeader('zip'));
0 ignored issues
show
Bug introduced by
The method hasSharedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
455
        $this->assertNull($loaded->getPayload());
456
457
        $decrypter->decryptUsingKeySet($loaded, $this->getSymmetricKeySet(), $index);
0 ignored issues
show
Bug introduced by
It seems like $loaded defined by \Jose\Loader::load($encrypted) on line 449 can also be of type object<Jose\Object\JWSInterface>; however, Jose\Decrypter::decryptUsingKeySet() does only seem to accept object<Jose\Object\JWEInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
458
459
        $this->assertEquals(0, $index);
460
        $this->assertTrue(is_array($loaded->getPayload()));
461
        $this->assertEquals($this->getKeySetToEncrypt(), new JWKSet($loaded->getPayload()));
0 ignored issues
show
Documentation introduced by
$loaded->getPayload() is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
462
    }
463
464
    public function testEncryptAndLoadCompactKeyAgreement()
465
    {
466
        $encrypter = EncrypterFactory::createEncrypter(['ECDH-ES', 'A192CBC-HS384'], ['DEF'], new FakeLogger());
467
        $decrypter = DecrypterFactory::createDecrypter(['ECDH-ES', 'A192CBC-HS384'], ['DEF'], new FakeLogger());
468
469
        $jwe = JWEFactory::createJWE(['user_id' => '1234', 'exp' => time() + 3600]);
470
        $jwe = $jwe->withSharedProtectedHeaders([
471
            'kid' => 'e9bc097a-ce51-4036-9562-d2ade882db0d',
472
            'enc' => 'A192CBC-HS384',
473
            'alg' => 'ECDH-ES',
474
        ]);
475
476
        $jwe = $jwe->addRecipient(
477
            $this->getECDHRecipientPublicKey()
478
        );
479
480
        $encrypter->encrypt($jwe);
481
482
        $loaded = Loader::load($jwe->toFlattenedJSON(0));
483
484
        $this->assertInstanceOf(JWEInterface::class, $loaded);
485
        $this->assertEquals('ECDH-ES', $loaded->getSharedProtectedHeader('alg'));
0 ignored issues
show
Bug introduced by
The method getSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
486
        $this->assertEquals('A192CBC-HS384', $loaded->getSharedProtectedHeader('enc'));
487
        $this->assertFalse($loaded->hasSharedProtectedHeader('zip'));
0 ignored issues
show
Bug introduced by
The method hasSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
488
        $this->assertNull($loaded->getPayload());
489
490
        $decrypter->decryptUsingKeySet($loaded, $this->getPrivateKeySet(), $index);
0 ignored issues
show
Bug introduced by
It seems like $loaded defined by \Jose\Loader::load($jwe->toFlattenedJSON(0)) on line 482 can also be of type object<Jose\Object\JWSInterface>; however, Jose\Decrypter::decryptUsingKeySet() does only seem to accept object<Jose\Object\JWEInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
491
492
        $this->assertEquals(0, $index);
493
        $this->assertTrue($loaded->hasClaims());
494
        $this->assertTrue($loaded->hasClaim('user_id'));
495
        $this->assertEquals('1234', $loaded->getClaim('user_id'));
496
    }
497
498
    public function testEncryptAndLoadCompactKeyAgreementWithWrappingCompact()
499
    {
500
        $encrypter = EncrypterFactory::createEncrypter(['ECDH-ES+A256KW', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
501
        $decrypter = DecrypterFactory::createDecrypter(['ECDH-ES+A256KW', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
502
503
        $jwe = JWEFactory::createJWE('Live long and Prosper.');
504
        $jwe = $jwe->withSharedProtectedHeaders([
505
            'kid' => 'e9bc097a-ce51-4036-9562-d2ade882db0d',
506
            'enc' => 'A256CBC-HS512',
507
            'alg' => 'ECDH-ES+A256KW',
508
        ]);
509
510
        $jwe = $jwe->addRecipient(
511
            $this->getECDHRecipientPublicKey()
512
        );
513
514
        $encrypter->encrypt($jwe);
515
516
        $loaded = Loader::load($jwe->toFlattenedJSON(0));
517
518
        $this->assertInstanceOf(JWEInterface::class, $loaded);
519
        $this->assertEquals('ECDH-ES+A256KW', $loaded->getSharedProtectedHeader('alg'));
0 ignored issues
show
Bug introduced by
The method getSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
520
        $this->assertEquals('A256CBC-HS512', $loaded->getSharedProtectedHeader('enc'));
521
        $this->assertFalse($loaded->hasSharedProtectedHeader('zip'));
0 ignored issues
show
Bug introduced by
The method hasSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
522
        $this->assertFalse($loaded->hasSharedHeader('zip'));
0 ignored issues
show
Bug introduced by
The method hasSharedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
523
        $this->assertNull($loaded->getPayload());
524
525
        $decrypter->decryptUsingKeySet($loaded, $this->getPrivateKeySet(), $index);
0 ignored issues
show
Bug introduced by
It seems like $loaded defined by \Jose\Loader::load($jwe->toFlattenedJSON(0)) on line 516 can also be of type object<Jose\Object\JWSInterface>; however, Jose\Decrypter::decryptUsingKeySet() does only seem to accept object<Jose\Object\JWEInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
526
527
        $this->assertEquals(0, $index);
528
        $this->assertTrue(is_string($loaded->getPayload()));
529
        $this->assertEquals('Live long and Prosper.', $loaded->getPayload());
530
    }
531
532
    public function testEncryptAndLoadWithGCMAndAAD()
533
    {
534
        $encrypter = EncrypterFactory::createEncrypter(['ECDH-ES+A256KW', 'A256GCM'], ['DEF'], new FakeLogger());
535
536
        $jwe = JWEFactory::createJWE(
537
            'Live long and Prosper.',
538
            [
539
                'kid' => 'e9bc097a-ce51-4036-9562-d2ade882db0d',
540
                'enc' => 'A256GCM',
541
                'alg' => 'ECDH-ES+A256KW',
542
            ],
543
            [],
544
            'foo,bar,baz'
545
        );
546
547
        $jwe = $jwe->addRecipient(
548
            $this->getECDHRecipientPublicKey()
549
        );
550
551
        $encrypter->encrypt($jwe);
552
553
        $loaded = Loader::load($jwe->toFlattenedJSON(0));
554
555
        $decrypter = DecrypterFactory::createDecrypter(['A256GCM', 'ECDH-ES+A256KW'], ['DEF'], new FakeLogger());
556
557
        $this->assertInstanceOf(JWEInterface::class, $loaded);
558
        $this->assertEquals('ECDH-ES+A256KW', $loaded->getSharedProtectedHeader('alg'));
0 ignored issues
show
Bug introduced by
The method getSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
559
        $this->assertEquals('A256GCM', $loaded->getSharedProtectedHeader('enc'));
560
        $this->assertFalse($loaded->hasSharedProtectedHeader('zip'));
0 ignored issues
show
Bug introduced by
The method hasSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
561
        $this->assertFalse($loaded->hasSharedHeader('zip'));
0 ignored issues
show
Bug introduced by
The method hasSharedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
562
        $this->assertNull($loaded->getPayload());
563
564
        $decrypter->decryptUsingKeySet($loaded, $this->getPrivateKeySet(), $index);
0 ignored issues
show
Bug introduced by
It seems like $loaded defined by \Jose\Loader::load($jwe->toFlattenedJSON(0)) on line 553 can also be of type object<Jose\Object\JWSInterface>; however, Jose\Decrypter::decryptUsingKeySet() does only seem to accept object<Jose\Object\JWEInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
565
566
        $this->assertEquals(0, $index);
567
        $this->assertTrue(is_string($loaded->getPayload()));
568
        $this->assertEquals('Live long and Prosper.', $loaded->getPayload());
569
    }
570
571
    public function testEncryptAndLoadCompactKeyAgreementWithWrapping()
572
    {
573
        $encrypter = EncrypterFactory::createEncrypter(['RSA-OAEP-256', 'ECDH-ES+A256KW', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
574
        $decrypter = DecrypterFactory::createDecrypter(['RSA-OAEP-256', 'ECDH-ES+A256KW', 'A256CBC-HS512'], ['DEF'], new FakeLogger());
575
576
        $jwe = JWEFactory::createJWE('Live long and Prosper.');
577
        $jwe = $jwe->withSharedProtectedHeaders(['enc' => 'A256CBC-HS512']);
578
579
        $jwe = $jwe->addRecipient(
580
            $this->getECDHRecipientPublicKey(),
581
            ['kid' => 'e9bc097a-ce51-4036-9562-d2ade882db0d', 'alg' => 'ECDH-ES+A256KW']
582
        );
583
        $jwe = $jwe->addRecipient(
584
            $this->getRSARecipientKey(),
585
            ['kid' => '123456789', 'alg' => 'RSA-OAEP-256']
586
        );
587
588
        $encrypter->encrypt($jwe);
589
590
        $loaded = Loader::load($jwe->toJSON());
591
592
        $this->assertEquals(2, $loaded->countRecipients());
0 ignored issues
show
Bug introduced by
The method countRecipients does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
593
594
        $this->assertInstanceOf(JWEInterface::class, $loaded);
595
        $this->assertEquals('A256CBC-HS512', $loaded->getSharedProtectedHeader('enc'));
0 ignored issues
show
Bug introduced by
The method getSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
596
        $this->assertEquals('ECDH-ES+A256KW', $loaded->getRecipient(0)->getHeader('alg'));
0 ignored issues
show
Bug introduced by
The method getRecipient does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
597
        $this->assertEquals('RSA-OAEP-256', $loaded->getRecipient(1)->getHeader('alg'));
598
        $this->assertFalse($loaded->hasSharedHeader('zip'));
0 ignored issues
show
Bug introduced by
The method hasSharedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
599
        $this->assertFalse($loaded->hasSharedProtectedHeader('zip'));
0 ignored issues
show
Bug introduced by
The method hasSharedProtectedHeader does only exist in Jose\Object\JWEInterface, but not in Jose\Object\JWSInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
600
        $this->assertNull($loaded->getPayload());
601
602
        $decrypter->decryptUsingKeySet($loaded, $this->getPrivateKeySet(), $index);
0 ignored issues
show
Bug introduced by
It seems like $loaded defined by \Jose\Loader::load($jwe->toJSON()) on line 590 can also be of type object<Jose\Object\JWSInterface>; however, Jose\Decrypter::decryptUsingKeySet() does only seem to accept object<Jose\Object\JWEInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
603
604
        $this->assertEquals(0, $index);
605
        $this->assertTrue(is_string($loaded->getPayload()));
606
        $this->assertEquals('Live long and Prosper.', $loaded->getPayload());
607
    }
608
609
    /**
610
     * @return JWK
611
     */
612
    private function getKeyToEncrypt()
613
    {
614
        $key = new JWK([
615
            'kty' => 'EC',
616
            'use' => 'enc',
617
            'crv' => 'P-256',
618
            'x'   => 'f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU',
619
            'y'   => 'x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0',
620
            'd'   => 'jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI',
621
        ]);
622
623
        return $key;
624
    }
625
626
    /**
627
     * @return JWKSet
628
     */
629
    private function getKeySetToEncrypt()
630
    {
631
        $key = new JWK([
632
            'kty' => 'EC',
633
            'use' => 'enc',
634
            'crv' => 'P-256',
635
            'x'   => 'f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU',
636
            'y'   => 'x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0',
637
            'd'   => 'jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI',
638
        ]);
639
640
        $key_set = new JWKSet();
641
        $key_set->addKey($key);
642
643
        return $key_set;
644
    }
645
646
    /**
647
     * @return JWK
648
     */
649
    private function getRSARecipientKey()
650
    {
651
        $key = new JWK([
652
            'kty' => 'RSA',
653
            'use' => 'enc',
654
            'n'   => 'tpS1ZmfVKVP5KofIhMBP0tSWc4qlh6fm2lrZSkuKxUjEaWjzZSzs72gEIGxraWusMdoRuV54xsWRyf5KeZT0S-I5Prle3Idi3gICiO4NwvMk6JwSBcJWwmSLFEKyUSnB2CtfiGc0_5rQCpcEt_Dn5iM-BNn7fqpoLIbks8rXKUIj8-qMVqkTXsEKeKinE23t1ykMldsNaaOH-hvGti5Jt2DMnH1JjoXdDXfxvSP_0gjUYb0ektudYFXoA6wekmQyJeImvgx4Myz1I4iHtkY_Cp7J4Mn1ejZ6HNmyvoTE_4OuY1uCeYv4UyXFc1s1uUyYtj4z57qsHGsS4dQ3A2MJsw',
655
            'e'   => 'AQAB',
656
        ]);
657
658
        return $key;
659
    }
660
661
    /**
662
     * @return JWK
663
     */
664
    private function getRSARecipientKeyWithAlgorithm()
665
    {
666
        $key = new JWK([
667
            'kty' => 'RSA',
668
            'use' => 'enc',
669
            'alg' => 'RSA-OAEP',
670
            'n'   => 'tpS1ZmfVKVP5KofIhMBP0tSWc4qlh6fm2lrZSkuKxUjEaWjzZSzs72gEIGxraWusMdoRuV54xsWRyf5KeZT0S-I5Prle3Idi3gICiO4NwvMk6JwSBcJWwmSLFEKyUSnB2CtfiGc0_5rQCpcEt_Dn5iM-BNn7fqpoLIbks8rXKUIj8-qMVqkTXsEKeKinE23t1ykMldsNaaOH-hvGti5Jt2DMnH1JjoXdDXfxvSP_0gjUYb0ektudYFXoA6wekmQyJeImvgx4Myz1I4iHtkY_Cp7J4Mn1ejZ6HNmyvoTE_4OuY1uCeYv4UyXFc1s1uUyYtj4z57qsHGsS4dQ3A2MJsw',
671
            'e'   => 'AQAB',
672
        ]);
673
674
        return $key;
675
    }
676
677
    /**
678
     * @return JWK
679
     */
680
    private function getSigningKey()
681
    {
682
        $key = new JWK([
683
            'kty'     => 'EC',
684
            'key_ops' => ['sign', 'verify'],
685
            'crv'     => 'P-256',
686
            'x'       => 'f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU',
687
            'y'       => 'x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0',
688
            'd'       => 'jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI',
689
        ]);
690
691
        return $key;
692
    }
693
694
    /**
695
     * @return JWK
696
     */
697
    private function getECDHRecipientPublicKey()
698
    {
699
        $key = new JWK([
700
            'kty'     => 'EC',
701
            'key_ops' => ['encrypt', 'decrypt'],
702
            'crv'     => 'P-256',
703
            'x'       => 'f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU',
704
            'y'       => 'x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0',
705
        ]);
706
707
        return $key;
708
    }
709
710
    /**
711
     * @return JWK
712
     */
713
    private function getDirectKey()
714
    {
715
        $key = new JWK([
716
            'kid'     => 'DIR_1',
717
            'key_ops' => ['encrypt', 'decrypt'],
718
            'kty'     => 'oct',
719
            'k'       => Base64Url::encode(hex2bin('00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F')),
720
        ]);
721
722
        return $key;
723
    }
724
}
725