puppet-sec-lint 0.1.2 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +4 -2
  3. data/.idea/puppet-sec-lint.iml +7 -4
  4. data/Gemfile +3 -1
  5. data/Gemfile.lock +14 -1
  6. data/README.md +36 -17
  7. data/_config.yml +1 -0
  8. data/docs/404.html +24 -0
  9. data/docs/Gemfile +30 -0
  10. data/docs/Gemfile.lock +275 -0
  11. data/docs/_config.yml +41 -0
  12. data/docs/_posts/2021-05-03-welcome-to-jekyll.markdown +25 -0
  13. data/docs/_site/404.html +71 -0
  14. data/docs/_site/feed.xml +13 -0
  15. data/docs/_site/index.html +1 -0
  16. data/docs/_site/jekyll/update/2021/05/03/welcome-to-jekyll.html +77 -0
  17. data/docs/hard-coded-credentials.md +17 -0
  18. data/docs/images/puppet-sec-lint_console.png +0 -0
  19. data/docs/images/puppet-sec-lint_vscode.png +0 -0
  20. data/docs/index.md +6 -0
  21. data/exe/puppet-sec-lint +81 -15
  22. data/file.pp +77 -0
  23. data/lib/configurations/configuration.rb +2 -1
  24. data/lib/configurations/regex_configuration.rb +9 -0
  25. data/lib/facades/configuration_file_facade.rb +3 -1
  26. data/lib/facades/configuration_page_facade.rb +6 -0
  27. data/lib/lol.pp +6 -6
  28. data/lib/puppet-sec-lint/version.rb +3 -1
  29. data/lib/rule_engine.rb +15 -3
  30. data/lib/rules/admin_by_default_rule.rb +33 -0
  31. data/lib/rules/cyrillic_homograph_attack.rb +27 -0
  32. data/lib/rules/empty_password_rule.rb +35 -0
  33. data/lib/rules/hard_coded_credentials_rule.rb +22 -31
  34. data/lib/rules/invalid_ip_addr_binding_rule.rb +37 -0
  35. data/lib/rules/no_http_rule.rb +26 -9
  36. data/lib/rules/rule.rb +72 -0
  37. data/lib/rules/suspicious_comment_rule.rb +28 -0
  38. data/lib/rules/use_weak_crypto_algorithms_rule.rb +28 -0
  39. data/lib/servers/language_server.rb +101 -0
  40. data/lib/servers/linter_server.rb +52 -0
  41. data/lib/settings.ini +39 -0
  42. data/lib/{sin.rb → sin/sin.rb} +6 -1
  43. data/lib/sin/sin_type.rb +44 -0
  44. data/lib/test.txt +15 -0
  45. data/lib/test2.rb +16 -0
  46. data/lib/test3.rb +32 -0
  47. data/lib/test_new.rb +19 -0
  48. data/puppet-sec-lint-0.5.3.gem +0 -0
  49. data/puppet-sec-lint.gemspec +7 -1
  50. metadata +139 -6
  51. data/lib/language_server.rb +0 -78
  52. data/lib/sin_type.rb +0 -12
@@ -15,5 +15,6 @@ DisplayField = {
15
15
  TextBox: "textbox",
16
16
  CheckBox: "checkbox",
17
17
  NumericBox: "numericbox",
18
- SelectBox: "selectbox"
18
+ SelectBox: "selectbox",
19
+ RegexBox: "regexbox"
19
20
  }
@@ -0,0 +1,9 @@
1
+ require_relative 'configuration'
2
+
3
+ class RegexConfiguration < Configuration
4
+
5
+ def initialize(name, value, description)
6
+ super
7
+ @displayfield=DisplayField[:RegexBox]
8
+ end
9
+ end
@@ -13,7 +13,7 @@ class ConfigurationFileFacade
13
13
  when DisplayField[:SelectBox]
14
14
  ini[rule][configuration.id] = configuration.value.join(',')
15
15
  else
16
- ini[rule][configuration.id] = configuration.value
16
+ ini[rule][configuration.id] = configuration.value.to_s
17
17
  end
18
18
  end
19
19
  end
@@ -32,6 +32,8 @@ class ConfigurationFileFacade
32
32
  case configuration.displayfield
33
33
  when DisplayField[:SelectBox]
34
34
  configuration.value = ini[rule][configuration.id].split(',')
35
+ when DisplayField[:RegexBox]
36
+ configuration.value = Regexp.new ini[rule][configuration.id]
35
37
  else
36
38
  configuration.value = ini[rule][configuration.id]
37
39
  end
@@ -50,6 +50,8 @@ class ConfigurationPageFacade
50
50
  return_value+="#{option}\n"
51
51
  end
52
52
  return_value += "</textarea>"
53
+ when DisplayField[:TextBox], DisplayField[:RegexBox]
54
+ return_value += "<input type=\"text\" id=\"#{configuration.id}\" name=\"#{configuration.id}\" value=\"#{configuration.value.to_s}\" size=\"#{configuration.value.to_s.length()}\"><br>\n"
53
55
  end
54
56
 
55
57
  return_value += "<p style=\"color:gray\">#{configuration.description}</p>\n<br>\n"
@@ -71,6 +73,10 @@ class ConfigurationPageFacade
71
73
 
72
74
  when DisplayField[:SelectBox]
73
75
  configuration.value = new_conf[configuration.id].split(/\r?\n/).delete_if(&:empty?)
76
+
77
+ when DisplayField[:RegexBox]
78
+ configuration.value = Regexp.new new_conf[configuration.id]
79
+
74
80
  else
75
81
  configuration.value = new_conf[configuration.id]
76
82
  end
data/lib/lol.pp CHANGED
@@ -8,17 +8,17 @@
8
8
  # the following code addresses the bug: https://bugs.launchpad.net/keystone/+bug/1472285 .
9
9
 
10
10
  class consul_template::service (
11
- $rpc_password = '{6ad470ec62b0511b63340dca2950d750181598efnHKvN1ge',
12
- $admin_username = 'admin',
13
- $password = 'ceilometer',
14
- $admin_password = 'admin',
11
+ $pass = lols(3),
12
+ $aijoijooiumihhn_password = 'pe-puppet'
13
+ $admin = 'ceisssesrelometer',
14
+ $aijoijooiumihhn_password = '(adiyu(guygmin',
15
15
  ) {
16
16
  exec { 'network-restart':
17
17
  command => 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDM release-runner key',
18
18
  path => '/usr/bin:/usr/sbin:/bin:/sbin',
19
19
  refreshonly => true,
20
20
  vmware_md5 => 'LOL',
21
- autho => 'MD5',
21
+ autho => 'MDi09i09i5',
22
22
  cmd => 'virsh secret-define --file ${secret_xml} && virsh secret-set-value --secret ${rbd_secret_uuid} --base64 $(ceph auth get-key client.${user})',
23
23
  $auth_uri => 'http://127.0.0.1:5000',
24
24
  'bind_address' => '0.0.0.0',
@@ -80,4 +80,4 @@ UcXHbA==
80
80
  replace => true,
81
81
  require => File['/var/lib/gerrit/.ssh']
82
82
  }
83
- }
83
+ }
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PuppetSecLint
4
- VERSION = "0.1.2"
4
+ VERSION = "0.5.4"
5
+ YEAR = "2021"
6
+ AUTHOR = "Tiago Ribeiro"
5
7
  end
data/lib/rule_engine.rb CHANGED
@@ -2,18 +2,30 @@ require 'puppet-lint'
2
2
  require_relative 'rules/rule'
3
3
  require_relative 'rules/hard_coded_credentials_rule'
4
4
  require_relative 'rules/no_http_rule'
5
+ require_relative 'rules/admin_by_default_rule'
6
+ require_relative 'rules/empty_password_rule'
7
+ require_relative 'rules/invalid_ip_addr_binding_rule'
8
+ require_relative 'rules/suspicious_comment_rule'
9
+ require_relative 'rules/use_weak_crypto_algorithms_rule'
10
+ require_relative 'rules/cyrillic_homograph_attack'
5
11
 
6
12
 
7
13
  class RuleEngine
8
- @rules=[HardCodedCredentialsRule,NoHTTPRule]
14
+ @rules=[HardCodedCredentialsRule,NoHTTPRule,AdminByDefaultRule,EmptyPasswordRule,InvalidIPAddrBindingRule,UseWeakCryptoAlgorithmsRule,SuspiciousCommentRule,CyrillicHomographAttack]
9
15
 
10
16
  class << self
11
17
  attr_accessor :rules
12
18
  end
13
19
 
14
20
  def self.getTokens(code)
15
- lexer = PuppetLint::Lexer.new
16
- tokens = lexer.tokenise(code)
21
+ begin
22
+ lexer = PuppetLint::Lexer.new
23
+ tokens = lexer.tokenise(code)
24
+ rescue
25
+ puts "Error in getting tokens from Puppet-Lint"
26
+ tokens = []
27
+ end
28
+
17
29
  return tokens
18
30
  end
19
31
 
@@ -0,0 +1,33 @@
1
+ require_relative '../configurations/list_configuration'
2
+
3
+ class AdminByDefaultRule < Rule
4
+ @name = "Admin by default"
5
+
6
+ @credentials = /user|usr|pass(word|_|$)|pwd/
7
+
8
+ @credentials_conf = RegexConfiguration.new("Regular expression of words present in credentials", @credentials, "Regular expression of words that if present indicate the existence of a secret.")
9
+
10
+ @configurations+=[@credentials_conf]
11
+
12
+ def self.AnalyzeTokens(tokens)
13
+ result = []
14
+
15
+ ftokens = self.get_tokens(tokens,'admin')
16
+ ftokens.each do |token|
17
+ token_value = token.value.downcase
18
+ token_type = token.type.to_s
19
+ if ["EQUALS", "FARROW"].include? token.prev_code_token.type.to_s
20
+ prev_token = token.prev_code_token
21
+ left_side = prev_token.prev_code_token
22
+ if left_side.value.downcase =~ @credentials_conf.value and ["VARIABLE", "NAME"].include? left_side.type.to_s
23
+ if token_value == 'admin'
24
+ result.append(Sin.new(SinType::AdminByDefault, left_side.line, left_side.column, token.line, token.column+token_value.length))
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ return result
31
+ end
32
+
33
+ end
@@ -0,0 +1,27 @@
1
+ require_relative '../configurations/list_configuration'
2
+
3
+ class CyrillicHomographAttack < Rule
4
+ @name = "Cyrillic Homograph attack"
5
+
6
+ @site_w_cyrillic = /^(http(s)?:\/\/)?.*\p{Cyrillic}+/
7
+
8
+ @site_w_cyrillic_conf = RegexConfiguration.new("Regular expression of links with Cyrillic characters", @site_w_cyrillic, "Regular expression of website links that have Cyrillic characters.")
9
+
10
+ @configurations+=[@site_w_cyrillic_conf]
11
+
12
+ def self.AnalyzeTokens(tokens)
13
+ result = []
14
+
15
+ ftokens = self.filter_tokens(tokens)
16
+ tokens.each do |token|
17
+ token_value = token.value.downcase
18
+ token_type = token.type.to_s
19
+ if ["STRING", "SSTRING"].include? token_type and token_value =~ @site_w_cyrillic_conf.value
20
+ result.append(Sin.new(SinType::CyrillicHomographAttack, token.line, token.column, token.line, token.column+token_value.length))
21
+ end
22
+ end
23
+
24
+ return result
25
+ end
26
+
27
+ end
@@ -0,0 +1,35 @@
1
+ require_relative '../configurations/list_configuration'
2
+
3
+ class EmptyPasswordRule < Rule
4
+ @default_trigger_words = %w[pwd password pass]
5
+ @password = /pass(word|_|$)|pwd/
6
+
7
+ @trigger_words_conf = ListConfiguration.new("List of trigger words", @default_trigger_words, "List of words that identify a password variable")
8
+ @password_conf = RegexConfiguration.new("Regular expression of password name", @password, "Regular expression of names used for password variables.")
9
+
10
+ @configurations+=[@trigger_words_conf, @password_conf]
11
+
12
+ @name = "Check empty password"
13
+
14
+ def self.AnalyzeTokens(tokens)
15
+ result = []
16
+
17
+ ftokens = self.get_string_tokens(tokens,'')
18
+ ftokens.each do |token|
19
+ token_value = token.value.downcase
20
+ token_type = token.type.to_s
21
+ if ["EQUALS", "FARROW"].include? token.prev_code_token.type.to_s
22
+ prev_token = token.prev_code_token
23
+ left_side = prev_token.prev_code_token
24
+ if left_side.value.downcase =~ @password_conf.value and ["VARIABLE", "NAME"].include? left_side.type.to_s
25
+ if token_value == ''
26
+ result.append(Sin.new(SinType::EmptyPassword, prev_token.line, prev_token.column, token.line, token.column+token_value.length))
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ return result
33
+ end
34
+
35
+ end
@@ -1,40 +1,34 @@
1
1
  require_relative '../configurations/list_configuration'
2
+ require_relative '../configurations/regex_configuration'
2
3
 
3
4
  class HardCodedCredentialsRule < Rule
4
- @default_trigger_words = %w[pwd password pass uuid key crypt secret certificate id cert token ssh_key md5 rsa ssl]
5
- @trigger_words_conf = ListConfiguration.new("List of trigger words", @default_trigger_words, "List of words that identify a variable with credentials")
6
- @test_conf = BooleanConfiguration.new("Test configuration", true, "This is just a test configuration")
5
+ @not_considered_creds = %w[pe-puppet pe-webserver pe-puppetdb pe-postgres pe-console-services pe-orchestration-services pe-ace-server pe-bolt-server]
6
+ @invalid_values = %w[undefined unset www-data wwwrun www no yes [] root]
7
+ @secrets = /user|usr|pass(word|_|$)|pwd|key|secret/
8
+ @non_secrets = /gpg|path|type|buff|zone|mode|tag|header|scheme|length|guid/
9
+
10
+ @not_considered_creds_conf = ListConfiguration.new("List of known words not considered in credentials", @not_considered_creds, "List of words not considered secrets by the community (https://puppet.com/docs/pe/2019.8/what_gets_installed_and_where.html#user_and_group_accounts_installed)")
11
+ @invalid_values_conf = ListConfiguration.new("List of invalid values in credentials", @invalid_values, "List of words that are not valid in a credential, advised by puppet specialists.")
12
+ @secrets_conf = RegexConfiguration.new("Regular expression of words present in credentials", @secrets, "Regular expression of words that if present indicate the existence of a secret.")
13
+ @non_secrets_conf = RegexConfiguration.new("Regular expression of words not present in credentials", @non_secrets, "Regular expression of words that if present discard the existence of a secret.")
7
14
 
8
15
  @name = "Hard Coded Credentials"
9
- @configurations+=[@trigger_words_conf,@test_conf]
16
+ @configurations+=[@not_considered_creds_conf, @invalid_values_conf, @secrets_conf, @non_secrets_conf]
10
17
 
11
18
  def self.AnalyzeTokens(tokens)
12
19
  result = []
13
20
 
14
- tokens.each do |indi_token|
15
- nxt_token = indi_token.next_code_token # next token which is not a white space
16
- if (!nxt_token.nil?) && (!indi_token.nil?)
17
- token_type = indi_token.type.to_s ### this gives type for current token
18
-
19
- token_line = indi_token.line ### this gives type for current token
20
- nxt_tok_line = nxt_token.line
21
-
22
- nxt_nxt_token = nxt_token.next_code_token # get the next next token to get key value pair
23
-
24
- if (!nxt_nxt_token.nil?)
25
- nxt_nxt_line = nxt_nxt_token.line
26
- if (token_type.eql? 'NAME') || (token_type.eql? 'VARIABLE')
27
- # puts "Token type: #{token_type}"
28
- if (token_line==nxt_nxt_line)
29
- token_valu = indi_token.value.downcase
30
- nxt_nxt_val = nxt_nxt_token.value.downcase
31
- nxt_nxt_type = nxt_nxt_token.type.to_s ## to handle false positives,
32
-
33
- if (self.TriggerWordInString(token_valu)) && ((nxt_nxt_val.length > 0)) && ((!nxt_nxt_type.eql? 'VARIABLE') && (!token_valu.include? "("))
34
- result.append(Sin.new(SinType::HardCodedCred, indi_token.line, indi_token.column, nxt_nxt_token.line, nxt_nxt_token.column+nxt_nxt_token.value.length))
35
- end
36
- end
37
- end
21
+ ftokens = self.filter_tokens(tokens)
22
+ ftokens.each do |token|
23
+ token_value = token.value.downcase
24
+ token_type = token.type.to_s
25
+ next_token = token.next_code_token
26
+ # accepts <VARIABLE> <EQUALS> secret OR <NAME> <FARROW> secret, checks if <VARIABLE> | <NAME> satisfy SECRETS but not satisfy NON_SECRETS
27
+ if ["VARIABLE", "NAME"].include? token_type and ["EQUALS", "FARROW"].include? next_token.type.to_s and token_value =~ @secrets_conf.value and !(token_value =~ @non_secrets_conf.value)
28
+ right_side_type = next_token.next_code_token.type.to_s
29
+ right_side_value = next_token.next_code_token.value.downcase
30
+ if ["STRING", "SSTRING"].include? right_side_type and right_side_value.length > 1 and !@invalid_values_conf.value.include? right_side_value and !(right_side_value =~ /::|\/|\.|\\/ ) and !@not_considered_creds_conf.value.include? right_side_value
31
+ result.append(Sin.new(SinType::HardCodedCred, token.line, token.column, next_token.next_code_token.line, next_token.next_code_token.column+right_side_value.length))
38
32
  end
39
33
  end
40
34
  end
@@ -42,7 +36,4 @@ class HardCodedCredentialsRule < Rule
42
36
  return result
43
37
  end
44
38
 
45
- def self.TriggerWordInString(string)
46
- return @trigger_words_conf.value.any? { |word| string.include?(word) }
47
- end
48
39
  end
@@ -0,0 +1,37 @@
1
+ require_relative '../configurations/list_configuration'
2
+
3
+ class InvalidIPAddrBindingRule < Rule
4
+ @name = "Invalid IP Address Binding"
5
+
6
+ @ip_addr_bin_regex = /^((http(s)?:\/\/)?0.0.0.0(:\d{1,5})?)$/
7
+
8
+ @ip_addr_bin_regex_conf = RegexConfiguration.new("Regular expression of an invalid IP address", @ip_addr_bin_regex, "Regular expression of an IP address considered invalid or insecure to use.")
9
+
10
+ @configurations+=[@ip_addr_bin_regex_conf]
11
+
12
+ def self.AnalyzeTokens(tokens)
13
+ result = []
14
+
15
+ ftokens = get_tokens(tokens,"0.0.0.0")
16
+ ftokens.each do |token|
17
+ token_value = token.value.downcase
18
+ token_type = token.type.to_s
19
+ if ["EQUALS", "FARROW"].include? token.prev_code_token.type.to_s
20
+ prev_token = token.prev_code_token
21
+ left_side = prev_token.prev_code_token
22
+ if token_value =~ @ip_addr_bin_regex_conf.value and ["VARIABLE", "NAME"].include? left_side.type.to_s
23
+ result.append(Sin.new(SinType::InvalidIPAddrBinding, left_side.line, left_side.column, token.line, token.column+token_value.length))
24
+ end
25
+ end
26
+ end
27
+
28
+ return result
29
+ end
30
+
31
+ def self.filter_tokens_per_value(tokens, token)
32
+ ftokens=tokens.find_all do |hash|
33
+ (hash.type.to_s == 'SSTRING' || hash.type.to_s == 'STRING') and hash.value.downcase.include? token
34
+ end
35
+ return ftokens
36
+ end
37
+ end
@@ -1,19 +1,36 @@
1
1
  require_relative '../configurations/list_configuration'
2
- require_relative '../sin'
3
- require_relative '../sin_type'
2
+ require_relative '../sin/sin'
3
+ require_relative '../sin/sin_type'
4
4
 
5
5
  class NoHTTPRule < Rule
6
- @name="No HTTP Connections"
6
+ @name="No HTTPS Connections"
7
+
8
+ @resources = %w[apt::source ::apt::source wget::fetch yumrepo yum:: aptly::mirror util::system_package yum::managed_yumrepo]
9
+ @keywords = %w[backport key download uri mirror]
10
+ @http = /^http:\/\/.+/
11
+ @whitelist = [] # Todo:Need to check how is this set up
12
+
13
+ @resources_conf = ListConfiguration.new("List of resources that can use HTTP", @resources, "List of resources that are known to not use HTTPS but that validate the transferred content with other secure methods.")
14
+ @keywords_conf = ListConfiguration.new("List of keywords for URLs", @keywords, "List of keywords that identify hyperlinks that should be analyzed.")
15
+ @http_conf = RegexConfiguration.new("Regular expression of a normal HTTP address", @http, "Regular expression that identifies the URL of a website using the regular non-secure HTTP protocol.")
16
+
17
+ @configurations+=[@resources_conf, @keywords_conf, @http_conf]
7
18
 
8
19
  def self.AnalyzeTokens(tokens)
9
20
  result = []
10
21
 
11
- tokens.each do |indi_token|
12
- token_valu = indi_token.value ### this gives each token
13
- token_valu = token_valu.downcase
14
- token_type = indi_token.type.to_s
15
- if (token_valu.include? "http://" ) && (!token_type.eql? "COMMENT")
16
- result.append(Sin.new(SinType::HttpWithoutTLS, indi_token.line, indi_token.column, indi_token.line, indi_token.column+indi_token.value.length))
22
+ ptokens = self.filter_resources(tokens, @resources_conf.value)
23
+ ctokens = self.filter_variables(ptokens, @keywords_conf.value)
24
+ if @whitelist
25
+ wtokens = self.filter_whitelist(ctokens)
26
+ else
27
+ wtokens = ptokens
28
+ end
29
+ wtokens.each do |token|
30
+ token_value = token.value.downcase
31
+ token_type = token.type.to_s
32
+ if (token_value =~ @http_conf.value)
33
+ result.append(Sin.new(SinType::HttpWithoutTLS, token.line, token.column, token.line, token.column+token_value.length))
17
34
  end
18
35
  end
19
36
 
data/lib/rules/rule.rb CHANGED
@@ -14,4 +14,76 @@ class Rule
14
14
  puts "Implement this"
15
15
  return
16
16
  end
17
+
18
+ def self.get_tokens(tokens, token)
19
+ ftokens=tokens.find_all do |hash|
20
+ (hash.type.to_s == 'NAME' || hash.type.to_s == 'VARIABLE' || hash.type.to_s == 'SSTRING' || hash.type.to_s == 'STRING') and hash.value.downcase.include? token
21
+ end
22
+ return ftokens
23
+ end
24
+
25
+ def self.filter_tokens(tokens)
26
+ ftokens=tokens.find_all do |hash|
27
+ (hash.type.to_s == 'SSTRING' || hash.type.to_s == 'STRING' || hash.type.to_s == 'VARIABLE' || hash.type.to_s == 'NAME')
28
+ end
29
+ return ftokens
30
+ end
31
+
32
+ def self.filter_resources(tokens, resources)
33
+ is_resource = false
34
+ brackets = 0
35
+ ftokens=tokens.find_all do |hash|
36
+
37
+ if resources.include? hash.value.downcase
38
+ is_resource = true
39
+ elsif is_resource and hash.type.to_s == "LBRACE"
40
+ brackets += 1
41
+ elsif is_resource and hash.type.to_s == "RBRACE"
42
+ brackets -=1
43
+ end
44
+
45
+ if is_resource and hash.type.to_s == "RBRACE" and brackets == 0
46
+ is_resource = false
47
+ end
48
+
49
+ if !is_resource
50
+ (hash.type.to_s == 'NAME' || hash.type.to_s == 'VARIABLE' || hash.type.to_s == 'SSTRING' || hash.type.to_s == 'STRING')
51
+ end
52
+ end
53
+ return ftokens
54
+ end
55
+
56
+ def self.get_string_tokens(tokens, token)
57
+ ftokens=tokens.find_all do |hash|
58
+ (hash.type.to_s == 'SSTRING' || hash.type.to_s == 'STRING') and hash.value.downcase.include? token
59
+ end
60
+ return ftokens
61
+ end
62
+
63
+ def self.get_comments(tokens)
64
+ ftokens=tokens.find_all do |hash|
65
+ (hash.type.to_s == 'COMMENT' || hash.type.to_s == 'MLCOMMENT' || hash.type.to_s == 'SLASH_COMMENT')
66
+ end
67
+ return ftokens
68
+ end
69
+
70
+ def self.filter_whitelist(tokens)
71
+ ftokens=tokens.find_all do |hash|
72
+ #!(@whitelist =~ hash.value.downcase)
73
+ true # TODO: Understand the whitelist
74
+ end
75
+ return ftokens
76
+ end
77
+
78
+ def self.filter_variables(tokens, keywords)
79
+ line = -1
80
+ kw_regex = Regexp.new keywords.join("|")
81
+ ftokens=tokens.find_all do |hash|
82
+ if (hash.type.to_s == 'VARIABLE' || hash.type.to_s == 'NAME') and hash.value.downcase =~ kw_regex
83
+ line = hash.line
84
+ elsif hash.line != line
85
+ hash
86
+ end
87
+ end
88
+ end
17
89
  end