Skip to content

Commit 3405184

Browse files
authored
Merge pull request #56 from jduigoudev/feature/ESOB006-Torch-Free
[ESOB006] iOS Sobriety - Usage of `AVCaptureDevice#torchMode` or `AVCaptureDevice#setTorchModeOn(level:)` must absolutely be avoided
2 parents e98816d + 45a03c9 commit 3405184

File tree

10 files changed

+203
-2
lines changed

10 files changed

+203
-2
lines changed

ios-plugin/RULES.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ Some rules have been already implemented in the plugin. Table of unimplemented r
1111
| ESOB002 | Thrifty Geolocation | Swift | |
1212
| ESOB003 | Motion Sensor Update Rate | Swift | |
1313
| ESOB004 | Disabled Dark Mode | Xml | Plist scanning |
14-
| ESOB006 | Torch-free | Swift | |
1514
| ESOB007 | Animation-free | Swift | |
1615

1716
### Social
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* ecoCode iOS plugin - Help the earth, adopt this green plugin for your applications
3+
* Copyright © 2022 Green code Initiative (https://www.ecocode.io/)
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package io.ecocode.ios.swift.checks.sobriety;
19+
20+
import io.ecocode.ios.swift.RegisterRule;
21+
import io.ecocode.ios.swift.Swift;
22+
import io.ecocode.ios.swift.antlr.generated.Swift5Parser;
23+
import io.ecocode.ios.checks.RuleCheck;
24+
import org.antlr.v4.runtime.tree.ParseTree;
25+
26+
/**
27+
* Check the use of "AVCaptureTorchMode.on", "setTorchModeOn(level: Float)", or "torchMode = .on" and triggers when set to true.
28+
*/
29+
@RegisterRule
30+
public class TorchFreeCheck extends RuleCheck {
31+
32+
public TorchFreeCheck() {
33+
super("ESOB006", Swift.RULES_PATH, Swift.REPOSITORY_KEY);
34+
}
35+
36+
@Override
37+
public void apply(ParseTree tree) {
38+
39+
if (tree instanceof Swift5Parser.ExpressionContext) {
40+
Swift5Parser.ExpressionContext id = (Swift5Parser.ExpressionContext) tree;
41+
String expressionText = id.getText();
42+
if (expressionText.contains("AVCaptureTorchMode.on") ||
43+
expressionText.contains("setTorchModeOn") ||
44+
expressionText.contains("torchMode=.on")) {
45+
this.recordIssue(ruleId, id.getStart().getStartIndex());
46+
}
47+
}
48+
}
49+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<img src="http://www.neomades.com/extern/partage/ecoCode/2sur5_1x.png">
2+
<p>Turning on the torch mode programmatically must absolutely be avoided because the flashlight is one of the most energy-intensive component.</p>
3+
<h2>Noncompliant Code Example</h2>
4+
<pre>
5+
AVCaptureTorchMode.on
6+
</pre>
7+
<pre>
8+
"setTorchModeOn(level: Float)"</pre>
9+
<pre>
10+
"torchMode = .on"
11+
</pre>

ios-plugin/swift-lang/src/main/resources/ecocode-swift-rules.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,22 @@
100100
"eco-design"
101101
],
102102
"type": "CODE_SMELL"
103+
},
104+
{
105+
"key": "ESOB006",
106+
"name": "Sobriety: Torch Free",
107+
"severity": "MAJOR",
108+
"description": "Usage of `AVCaptureDevice#torchMode` or `AVCaptureDevice#setTorchModeOn(level:)` must absolutely be avoided. These methods can be used to access the device's flashlight, which can be a potential security risk and should only be used when necessary.",
109+
"debt": {
110+
"function": "CONSTANT_ISSUE",
111+
"offset": "5min"
112+
},
113+
"tags": [
114+
"sobriety",
115+
"environment",
116+
"ecocode",
117+
"eco-design"
118+
],
119+
"type": "CODE_SMELL"
103120
}
104121
]

ios-plugin/swift-lang/src/main/resources/ecocode_swift_profile.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"EPOW001",
77
"EPOW002",
88
"ESOB001",
9-
"ESOB005"
9+
"ESOB005",
10+
"ESOB006"
1011
]
1112
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* ecoCode iOS plugin - Help the earth, adopt this green plugin for your applications
3+
* Copyright © 2022 Green code Initiative (https://www.ecocode.io/)
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package io.ecocode.ios.swift.checks.sobriety;
19+
20+
import io.ecocode.ios.swift.checks.CheckTestHelper;
21+
import org.junit.Test;
22+
import org.sonar.api.batch.sensor.internal.SensorContextTester;
23+
import org.sonar.api.batch.sensor.issue.Issue;
24+
import org.sonar.api.batch.sensor.issue.IssueLocation;
25+
26+
import static org.assertj.core.api.Assertions.assertThat;
27+
28+
public class TorchFreeCheckTest {
29+
30+
@Test
31+
public void should_detect_torch_on_usage() {
32+
assertTorchIssue("checks/sobriety/TorchFree_on_trigger.swift", 12);
33+
}
34+
35+
@Test
36+
public void should_detect_torch_typeInference_on_usage() {
37+
assertTorchIssue("checks/sobriety/TorchFree_typeInference_on_trigger.swift", 12);
38+
}
39+
40+
@Test
41+
public void should_detect_level_torch_usage() {
42+
assertTorchIssue("checks/sobriety/TorchFree_level_trigger.swift", 12);
43+
}
44+
45+
@Test
46+
public void should_not_detect_torch_usage() {
47+
SensorContextTester context = CheckTestHelper.analyzeTestFile("checks/sobriety/TorchFree_no_trigger.swift");
48+
assertThat(context.allIssues()).isEmpty();
49+
}
50+
51+
private void assertTorchIssue(String file, int line) {
52+
SensorContextTester context = CheckTestHelper.analyzeTestFile(file);
53+
assertThat(context.allIssues()).hasSize(1)
54+
.allSatisfy(issue -> {
55+
assertIssue(issue, line);
56+
});
57+
}
58+
59+
private void assertIssue(Issue issue, int line) {
60+
assertThat(issue.ruleKey().rule()).isEqualTo("ESOB006");
61+
assertThat(issue.ruleKey().repository()).isEqualTo("ecoCode-swift");
62+
IssueLocation location = issue.primaryLocation();
63+
assertThat(location.textRange().start().line()).isEqualTo(line);
64+
}
65+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import Foundation
2+
import SwiftUI
3+
import AVFoundation
4+
5+
final class AppDelegate: NSObject, UIApplicationDelegate {
6+
func application(
7+
_ application: UIApplication,
8+
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
9+
) -> Bool {
10+
11+
let device = AVCaptureDevice.default(for: AVMediaType.video)
12+
device.setTorchModeOn(level: AVCaptureDevice.maxAvailableTorchLevel / 2.0)
13+
return true
14+
}
15+
}
16+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Foundation
2+
import SwiftUI
3+
4+
final class AppDelegate: NSObject, UIApplicationDelegate {
5+
func application(
6+
_ application: UIApplication,
7+
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
8+
) -> Bool {
9+
return true
10+
}
11+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import Foundation
2+
import SwiftUI
3+
import AVFoundation
4+
5+
final class AppDelegate: NSObject, UIApplicationDelegate {
6+
func application(
7+
_ application: UIApplication,
8+
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
9+
) -> Bool {
10+
11+
let device = AVCaptureDevice.default(for: AVMediaType.video)
12+
device.torchMode = .on
13+
14+
return true
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import Foundation
2+
import SwiftUI
3+
import AVFoundation
4+
5+
final class AppDelegate: NSObject, UIApplicationDelegate {
6+
func application(
7+
_ application: UIApplication,
8+
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
9+
) -> Bool {
10+
11+
let device = AVCaptureDevice.default(for: AVMediaType.video)
12+
device.torchMode = AVCaptureTorchMode.on
13+
14+
return true
15+
}
16+
}

0 commit comments

Comments
 (0)