This file is indexed.

/usr/share/tdiary/contrib/plugin/profile.rb is in tdiary-contrib 3.2.2-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#
# profile.rb: profile plugin for tDiary
#
# usage:
#   profile(id[, service = :twitter])
#   - id: user ID for profile service
#   - service: profile service (default is :twitter)
#     Choose from :github, :twitter, :friendfeed, :iddy
#
# Copyright (C) 2009 by MATSUOKA Kohei < http://www.machu.jp/ >
# Distributed under the GPL.
#
require 'timeout'
require 'rexml/document'
require 'open-uri'
require 'digest/md5'
require 'pstore'

module ::Profile
  module Service
    # base class for profile services
    class Base
      # default attributes
      attr_reader :id
      attr_reader :image
      attr_reader :name
      attr_reader :mail
      attr_reader :description
      attr_reader :link

      # class instance variables
      class << self
        attr_reader :properties
        attr_reader :endpoint_proc
      end

      # set property and xpath pair for parse XML document
      def self.property(property, path)
        @properties ||= {}
        @properties[property] = path
      end

      # set endpoint proc (this proc is called by initialize method with id)
      def self.endpoint(&block)
        @endpoint_proc = block
      end

      def initialize(id, options = {})
        @id = id
        @options = options

        if self.class.endpoint_proc
          endpoint = self.class.endpoint_proc.call(id)
          doc = fetch(endpoint)
          parse(doc)
        end
      end

      # get a XML document from endpoint and create REXML::Document instance
      def fetch(endpoint)
        timeout(5) do
          open(endpoint) do |f|
            doc = REXML::Document.new(f)
          end
        end
      end

      # parse XML document with properties
      def parse(doc)
        self.class.properties.each do |property, path|
          if doc.elements[path]
            value = doc.elements[path].text
            instance_variable_set("@#{property}", value)
          end
        end
      end
    end

    # github.com
    class GitHub < Base
      property :name, 'name'
      property :mail, 'email'
      endpoint {|id| "https://api.github.com/users/#{id}" }

      def image
        # "http://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(@mail)}.jpg"
        Gravatar.new(@mail, @options).image
      end

      def link
        "http://github.com/#{@id}"
      end

      def fetch(endpoint)
        require 'json'
        timeout(5) do
          doc = open(endpoint) {|f| JSON.parse(f.read) }
        end
      end

      def parse(doc)
        self.class.properties.each do |property, key|
          instance_variable_set("@#{property}", doc[key]) if doc[key]
        end
      end
    end

    # twitter.com
    class Twitter < Base
      property :name, '//user/name'
      property :image, '//user/profile_image_url'
      property :description, '//user/description'
      endpoint {|id| "http://twitter.com/users/show/#{id}.xml" }

      def link
        "http://twitter.com/#{@id}"
      end
    end

    # friendfeed.com
    class FriendFeed < Base
      property :name, '//feed/name'
      property :description, '//feed/description'
      endpoint {|id| "http://friendfeed-api.com/v2/feed/#{id}?format=xml&num=0" }

      def image
        "http://friendfeed-api.com/v2/picture/#{id}"
      end

      def link
        "http://friendfeed.com/#{@id}"
      end
    end

    # iddy.jp
    # this class is based on iddy.rb
    class Iddy < Base
      ######################################################################
      # If you will modify or release another version of this code,
      # please get your own application key from iddy.jp and replace below.
      ######################################################################
      API_KEY = '9262ea8ffba962aabb4f1a1d3f1cfa953b11aa23' unless defined? API_KEY

      property :name, '//response/users/user/accountname'
      property :image, '//response/users/user/imageurl'
      property :description, '/response/users/user/profile'
      endpoint {|id| "http://iddy.jp/api/user/?apikey=#{API_KEY}&accountname=#{id}" }

      def link
        "http://iddy.jp/profile/#{@id}/"
      end
    end

    # gravatar.com
    class Gravatar < Base
      def image
        size = @options[:size] ? "?s=#{@options[:size]}" : ""
        "http://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(@id.downcase)}.jpg#{size}"
      end
    end

    class Hatena < Base
      def image
        prefix = id[0..1]
        "http://www.hatena.ne.jp/users/#{prefix}/#{id}/profile.gif"
      end

      def link
        "http://www.hatena.ne.jp/#{id}/"
      end
    end
  end
end

PROFILE_VERSION = '20090909'

def profile(id, service = :twitter, options = {})
  html = ''

  service_class = {
    :twitter => Profile::Service::Twitter,
    :github => Profile::Service::GitHub,
    :friendfeed => Profile::Service::FriendFeed,
    :iddy => Profile::Service::Iddy,
    :gravatar => Profile::Service::Gravatar,
    :hatena => Profile::Service::Hatena,
  }[service.to_s.downcase.to_sym]

  # TODO: create cache manager class

  # cache = "#{@cache_path}/profile.yaml"
  cache = "#{@cache_path}/profile.pstore"
  profile = nil
  # db = YAML::Store.new(cache)
  db = PStore.new(cache)
  db.transaction do
    key = service_class.name
    db[key] ||= {} # initialize db
    updated = db[key][:updated]
    if updated && (Time::now < updated + 60 * 60) && db[key][:version] == PROFILE_VERSION
      # use cache
      profile = db[key][:profile]
    else
      # get latest date and update cache
      begin
        profile = service_class.new(id, options)
      rescue Timeout::Error, StandardError
        return html << %Q{ <div class="profile">no profile</div> }
      end
      db[key][:updated] = Time::now
      db[key][:profile] = profile
      db[key][:version] = PROFILE_VERSION
    end
  end

  html << %Q{ <div class="profile"><a href="#{CGI.escapeHTML profile.link}"> }
  html << %Q{ <span class="profile-image"><img src="#{CGI.escapeHTML profile.image}" alt="profile image"></span> } if profile.image
  html << %Q{ <span class="profile-name">#{CGI.escapeHTML profile.name}</span> } if profile.name
  html << %Q{ <span class="profile-mail">#{CGI.escapeHTML profile.mail}</span> } if profile.mail
  html << %Q{ <span class="profile-description">#{CGI.escapeHTML profile.description}</span> } if profile.description
  html << %Q{ </a></div> }
end