This file is indexed.

/usr/share/tdiary/contrib/plugin/profile.rb is in tdiary-contrib 5.0.8-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
#
# profile.rb: profile plugin for tDiary
#
# usage:
#   profile(id[, service = :gravatar])
#   - id: user ID for profile service
#   - service: profile service (default is :gravatar)
#     Choose from :github, :gravatar, :hatena
#
# 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.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'
			property :image, 'avatar_url'
			endpoint {|id| "https://api.github.com/users/#{id}" }

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

			def fetch(endpoint)
				require 'json'
				Timeout.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
			# dummy class
		end

		# iddy.jp, for backward compatibility
		class Iddy < Base
			# dummy class
		end

		# gravatar.com
		class Gravatar < Base
			HOST = 'ja.gravatar.com' unless const_defined?(:HOST)
			endpoint {|id|
				hash = Digest::MD5.hexdigest(id.downcase)
				"https://#{HOST}/#{hash}.json"
			}

			def image
				size = @options[:size] ? "?s=#{@options[:size]}" : ""
				"#{@image_base}#{size}"
			end

			def fetch(endpoint)
				require 'json'
				Timeout.timeout(5) do
					begin
						doc = open(endpoint) {|f| JSON.parse(f.read) }
					rescue RuntimeError => err
						if err.message =~ /^redirection forbidden: /
							 endpoint.sub!(/www/, @options[:lang])
							 retry
						else
							 raise
						end
					end
				end
			end

			def parse(doc)
				instance_variable_set("@name", doc['entry'][0]['displayName'])
				instance_variable_set("@mail", @id)
				instance_variable_set("@image_base", doc['entry'][0]['thumbnailUrl'])
				instance_variable_set("@link", doc['entry'][0]['profileUrl'])
				instance_variable_set("@description", doc['entry'][0]['aboutMe'])
			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 = :gravatar, options = {})
	html = ''

	service_class = {
		:github => Profile::Service::GitHub,
		:gravatar => Profile::Service::Gravatar,
		:hatena => Profile::Service::Hatena,
	}[service.to_s.downcase.to_sym] || Profile::Service::Gravatar

	# 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.merge(lang: @conf.lang))
			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